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

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

RWT Commit : Cosmetic

File size: 31.1 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
[814]40// fail if the ZOMBI state is not used.
[297]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
[814]51// - size_t         nways   : number of associativity levels
[297]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 :
[814]60// - addr_t : address format to access the cache
[297]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
[814]73namespace soclib {
[297]74
75enum cache_slot_state_e
76{
77    CACHE_SLOT_STATE_EMPTY,
[477]78    CACHE_SLOT_STATE_VALID_CC,
[297]79    CACHE_SLOT_STATE_ZOMBI,
[477]80    CACHE_SLOT_STATE_VALID_NCC,
[297]81};
82
83//////////////////////////
84template<typename addr_t>
[814]85class GenericCache
[297]86//////////////////////////
87{
[771]88    typedef uint32_t data_t;
89    typedef uint32_t be_t;
[297]90
[823]91    data_t *r_data ;
92    addr_t *r_tag ;
93    int    *r_state;
94    bool   *r_lru ;
[297]95
[823]96    size_t m_ways;
97    size_t m_sets;
98    size_t m_words;
[297]99
[771]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 ;
[297]103
104    //////////////////////////////////////////////////////////////
105    inline data_t &cache_data(size_t way, size_t set, size_t word)
106    {
[823]107        return r_data[(way * m_sets * m_words) + (set * m_words) + word];
[297]108    }
109
110    //////////////////////////////////////////////
[393]111    inline addr_t &cache_tag(size_t way, size_t set)
[297]112    {
[823]113        return r_tag[(way * m_sets) + set];
[297]114    }
115
116    //////////////////////////////////////////////
117    inline bool &cache_lru(size_t way, size_t set)
118    {
[823]119        return r_lru[(way * m_sets) + set];
[297]120    }
[814]121
[297]122    //////////////////////////////////////////////
123    inline int &cache_state(size_t way, size_t set)
124    {
[823]125        return r_state[(way * m_sets) + set];
[297]126    }
127
[814]128
[297]129    /////////////////////////////////////////////////
130    inline void cache_set_lru(size_t way, size_t set)
131    {
[814]132        size_t way2;
[297]133
134        cache_lru(way, set) = true;
135
[814]136        for (way2 = 0; way2 < m_ways; way2++)
[297]137        {
[814]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++)
[297]142        {
[814]143            cache_lru(way2, set) = false;
144        }
[297]145    }
146
[393]147    ////////////////////////////////
[771]148    inline data_t be2mask(be_t be)
[297]149    {
150        data_t mask = 0;
[823]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;
[297]155        return mask;
156    }
157
158public:
159
[393]160    //////////////////////////////////////////
[771]161    GenericCache(const std::string &name,
[823]162                 size_t            nways,
163                 size_t            nsets,
164                 size_t            nwords)
[297]165        : m_ways(nways),
166          m_sets(nsets),
167          m_words(nwords),
168
169#define l2 soclib::common::uint32_log2
170
[823]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)))
[297]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
[771]188        std::cout << "constructing " << name << std::endl
[393]189          << "- nways  = " << nways << std::endl
190          << "- nsets  = " << nsets << std::endl
191          << "- nwords = " << nwords << std::endl
[814]192          << " m_x: " << m_x
[393]193          << " m_y: " << m_y
194          << " m_z: " << m_z
195          << std::endl;
[297]196#endif
197
[823]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];
[297]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    ////////////////////
[771]214    inline void reset()
[297]215    {
[823]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);
[297]220    }
221
[477]222    inline int get_cache_state(int way, int set)
223    {
224        return cache_state(way,set);
225    }
[814]226
[297]227    /////////////////////////////////////////////////////////////////////
228    // Read a single 32 bits word.
[814]229    // returns true if (matching tag) and (state == VALID)
230    // Both data & directory are accessed.
[297]231    /////////////////////////////////////////////////////////////////////
[814]232    inline bool read(addr_t  ad,
[771]233                     data_t* dt)
[297]234    {
[771]235        const addr_t tag  = m_z[ad];
236        const size_t set  = m_y[ad];
237        const size_t word = m_x[ad];
[297]238
[814]239        for (size_t way = 0; way < m_ways; way++)
[297]240        {
[823]241            if ((tag == cache_tag(way, set)) and
242                   ((cache_state(way, set) == CACHE_SLOT_STATE_VALID_CC) or
243                    (cache_state(way, set) == CACHE_SLOT_STATE_VALID_NCC)))
[297]244            {
245                *dt = cache_data(way, set, word);
246                cache_set_lru(way, set);
247                return true;
248            }
249        }
250        return false;
251    }
252
253    ////////////////////////////////////////////////////////////////////
254    // Read a single 32 bits word.
[814]255    // returns true if (matching tag) and (state == VALID)
256    // Both data & directory are accessed.
[297]257    // The selected way, set and word index are returned in case of hit.
258    /////////////////////////////////////////////////////////////////////
[814]259    inline bool read(addr_t ad,
[771]260                     data_t* dt,
261                     size_t* selway,
262                     size_t* selset,
[814]263                     size_t* selword)
[297]264    {
[771]265        const addr_t tag  = m_z[ad];
266        const size_t set  = m_y[ad];
267        const size_t word = m_x[ad];
[297]268
[814]269        for (size_t way = 0; way < m_ways; way++)
[297]270        {
[771]271            if ((tag == cache_tag(way, set)) and
[823]272                 ((cache_state(way, set) == CACHE_SLOT_STATE_VALID_CC) or
273                  (cache_state(way, set) == CACHE_SLOT_STATE_VALID_NCC)))
[297]274            {
275                *selway  = way;
276                *selset  = set;
277                *selword = word;
278                *dt = cache_data(way, set, word);
279                cache_set_lru(way, set);
280                return true;
281            }
282        }
283        return false;
284    }
285
286    ////////////////////////////////////////////////////////////////////
287    // Read a single 32 bits word when the ZOMBI state is used.
288    // Both data and directory are accessed.
289    // returns the access status in the state argument:
[814]290    // - VALID : (matching tag) and (state == VALID)
291    // - ZOMBI : (matching tag) and (state == ZOMBI)
[297]292    // - MISS  : no matching tag or EMPTY state
[814]293    // If VALID or ZOMBI, the data, the way, set and word index are
[297]294    // returned in the other arguments.
295    ////////////////////////////////////////////////////////////////////
[771]296    inline void read(addr_t  ad,
297                     data_t* dt,
298                     size_t* selway,
299                     size_t* selset,
300                     size_t* selword,
[814]301                     int*    state)
[297]302    {
[771]303        const addr_t tag  = m_z[ad];
304        const size_t set  = m_y[ad];
305        const size_t word = m_x[ad];
[297]306
[814]307        // default return values
[297]308        *state   = CACHE_SLOT_STATE_EMPTY;
309        *selway  = 0;
310        *selset  = 0;
311        *selword = 0;
312        *dt      = 0;
313
[814]314        for (size_t way = 0; way < m_ways; way++)
[297]315        {
[771]316            if (tag == cache_tag(way, set))  // matching tag
[297]317            {
[771]318                if (cache_state(way, set) == CACHE_SLOT_STATE_VALID_CC)
[297]319                {
[477]320                    *state   = CACHE_SLOT_STATE_VALID_CC;
[297]321                    *selway  = way;
322                    *selset  = set;
323                    *selword = word;
324                    *dt      = cache_data(way, set, word);
325                    cache_set_lru(way, set);
326                }
[771]327                else if (cache_state(way, set) == CACHE_SLOT_STATE_VALID_NCC)
[477]328                {
329                    *state   = CACHE_SLOT_STATE_VALID_NCC;
330                    *selway  = way;
331                    *selset  = set;
332                    *selword = word;
333                    *dt      = cache_data(way, set, word);
334                    cache_set_lru(way, set);
335                }
[771]336                else if (cache_state(way, set) == CACHE_SLOT_STATE_ZOMBI)
[297]337                {
338                    *state   = CACHE_SLOT_STATE_ZOMBI;
339                    *selway  = way;
340                    *selset  = set;
341                    *selword = word;
342                }
343            }
344        }
345    }
[814]346
[297]347    ////////////////////////////////////////////////////////////////////
348    // Read a single 32 bits word, without LRU update.
[814]349    // returns true if (matching tag) and (state == VALID)
350    // Both data & directory are accessed.
[297]351    // The selected way, set and word index are returned in case of hit.
352    /////////////////////////////////////////////////////////////////////
[814]353    inline bool read_neutral(addr_t  ad,
[771]354                             data_t* dt,
355                             size_t* selway,
356                             size_t* selset,
[814]357                             size_t* selword)
[297]358    {
[771]359        const addr_t tag  = m_z[ad];
360        const size_t set  = m_y[ad];
361        const size_t word = m_x[ad];
[297]362
[814]363        for (size_t way = 0; way < m_ways; way++)
[297]364        {
[823]365            if ((tag == cache_tag(way, set)) and
366                   ((cache_state(way, set) == CACHE_SLOT_STATE_VALID_CC) or
367                    (cache_state(way, set) == CACHE_SLOT_STATE_VALID_NCC)))
[297]368            {
369                *selway  = way;
370                *selset  = set;
371                *selword = word;
[823]372                *dt      = cache_data(way, set, word);
[297]373                return true;
374            }
375        }
376        return false;
377    }
378
379    /////////////////////////////////////////////////////////////////////////////
380    // Read one or two 32 bits word.
[814]381    // Both data & directory are accessed.
382    // Hit if (matching tag) and (valid == true) and (zombi == false)
[297]383    // If the addressed word is not the last in the cache line,
384    // two successive words are returned.
385    // The selected way, set and first word index are returned in case of hit.
386    // This function is used by the cc_vcache to get a 64 bits page table entry.
387    /////////////////////////////////////////////////////////////////////////////
[823]388    inline bool read(addr_t  ad,
389                     data_t* dt,
390                     data_t* dt_next,
391                     size_t* selway,
392                     size_t* selset,
393                     size_t* selword)
[297]394    {
[771]395        const addr_t tag  = m_z[ad];
396        const size_t set  = m_y[ad];
397        const size_t word = m_x[ad];
[297]398
[814]399        for (size_t way = 0; way < m_ways; way++)
[297]400        {
[823]401            if ((tag == cache_tag(way, set)) and
402                   ((cache_state(way, set) == CACHE_SLOT_STATE_VALID_CC)))
[297]403            {
[771]404                *dt = cache_data(way, set, word);
[814]405                if (word + 1 < m_words)
[297]406                {
[771]407                    *dt_next = cache_data(way, set, word + 1);
[297]408                }
409                *selway  = way;
410                *selset  = set;
411                *selword = word;
412                cache_set_lru(way, set);
413                return true;
414            }
415        }
416        return false;
417    }
418
[337]419    ////////////////////////////////////////////////////////////////////
420    // Read one or two 32 bits word.
421    // Both data and directory are accessed.
422    // returns the access status in the state argument:
[814]423    // - VALID : (matching tag) and (state == VALID)
424    // - ZOMBI : (matching tag) and (state == ZOMBI)
[337]425    // - MISS  : no matching tag or EMPTY state
[814]426    // If VALID or ZOMBI, the data, the way, set and word index are
[337]427    // returned in the other arguments.
428    ////////////////////////////////////////////////////////////////////
[771]429    inline void read(addr_t  ad,
430                     data_t* dt,
431                     data_t* dt_next,
432                     size_t* selway,
433                     size_t* selset,
434                     size_t* selword,
[814]435                     int*    state)
[337]436    {
[771]437        const addr_t tag  = m_z[ad];
438        const size_t set  = m_y[ad];
439        const size_t word = m_x[ad];
[337]440
[814]441        // default return values
[337]442        *state   = CACHE_SLOT_STATE_EMPTY;
443        *selway  = 0;
444        *selset  = 0;
445        *selword = 0;
446        *dt      = 0;
447
[814]448        for (size_t way = 0; way < m_ways; way++)
[337]449        {
[771]450            if (tag == cache_tag(way, set))  // matching tag
[337]451            {
452
[771]453                if (cache_state(way, set) == CACHE_SLOT_STATE_VALID_CC)
[337]454                {
[477]455                    *state   = CACHE_SLOT_STATE_VALID_CC;
[337]456                    *selway  = way;
457                    *selset  = set;
458                    *selword = word;
459                    *dt      = cache_data(way, set, word);
[814]460                    if (word + 1 < m_words)
[337]461                    {
462                        *dt_next = cache_data(way, set, word+1);
463                    }
464                    cache_set_lru(way, set);
465                }
[477]466
[771]467                else if (cache_state(way, set) == CACHE_SLOT_STATE_VALID_NCC)
[477]468                {
469                    *state   = CACHE_SLOT_STATE_VALID_NCC;
470                    *selway  = way;
471                    *selset  = set;
472                    *selword = word;
473                    *dt      = cache_data(way, set, word);
[814]474                    if (word + 1 < m_words)
[477]475                    {
[771]476                        *dt_next = cache_data(way, set, word + 1);
[477]477                    }
478                    cache_set_lru(way, set);
479                }
480
[771]481                else if (cache_state(way, set) == CACHE_SLOT_STATE_ZOMBI)
[337]482                {
483                    *state   = CACHE_SLOT_STATE_ZOMBI;
484                    *selway  = way;
485                    *selset  = set;
486                    *selword = word;
487                }
488            }
489        }
490    }
491
[297]492    ///////////////////////////////////////////////////////////////////////////////
493    // Checks the cache state for a given address.
[814]494    // Only the directory is accessed.
495    // returns true if (matching tag) and (state == VALID)
[297]496    // The selected way, set and first word index are returned in case of hit.
497    // This function can be used when we need to access the directory
498    // while we write in the data part with a different address in the same cycle.
499    ///////////////////////////////////////////////////////////////////////////////
[814]500    inline bool hit(addr_t  ad,
[771]501                    size_t* selway,
502                    size_t* selset,
503                    size_t* selword)
[297]504    {
[771]505        const addr_t tag  = m_z[ad];
506        const size_t set  = m_y[ad];
507        const size_t word = m_x[ad];
[297]508
[814]509        for (size_t way = 0; way < m_ways; way++)
[297]510        {
[823]511            if ((tag == cache_tag(way, set)) and
512                   ((cache_state(way, set) == CACHE_SLOT_STATE_VALID_CC) or
513                    (cache_state(way, set) == CACHE_SLOT_STATE_VALID_NCC)))
[297]514            {
515                *selway  = way;
516                *selset  = set;
517                *selword = word;
518                cache_set_lru(way, set);
519                return true;
520            }
521        }
522        return false;
523    }
[814]524
[297]525    ///////////////////////////////////////////////////////////////////////////////
[393]526    // Checks the cache state for a given address, when the ZOMBI state is used.
[814]527    // Only the directory is accessed.
[297]528    // Returns the access status in the state argument:
[814]529    // - VALID if (matching tag) and (state == VALID)
530    // - ZOMBI if (matching tag) and (state == ZOMBI)
[297]531    // - EMPTY if no match or (state == EMPTY)
532    // The selected way, set and first word index are returned if not empty.
533    // This function can be used when we need to access the directory
534    // while we write in the data part with a different address in the same cycle.
535    ///////////////////////////////////////////////////////////////////////////////
[814]536    inline void read_dir(addr_t  ad,
[771]537                         int*    state,
538                         size_t* way,
539                         size_t* set,
540                         size_t* word)
[297]541    {
[771]542        const addr_t ad_tag  = m_z[ad];
543        const size_t ad_set  = m_y[ad];
544        const size_t ad_word = m_x[ad];
[814]545        for (size_t _way = 0; _way < m_ways; _way++)
[297]546        {
[814]547            if ((ad_tag == cache_tag(_way, ad_set)) and
548                (cache_state(_way, ad_set) != CACHE_SLOT_STATE_EMPTY))
[297]549            {
550                *state = cache_state(_way, ad_set);
551                *way   = _way;
552                *set   = ad_set;
553                *word  = ad_word;
554                return;
555            }
556        }
[814]557
[297]558        // return value if not (VALID or ZOMBI)
559        *state = CACHE_SLOT_STATE_EMPTY;
560    }
561
562    ///////////////////////////////////////////////////////////////////////////////
563    // Checks the cache state for a slot (set,way), when the ZOMBI state is used.
[814]564    // Only the directory is accessed.
[297]565    // Returns the access status and the tag value in the state and tag argument.
566    ///////////////////////////////////////////////////////////////////////////////
[771]567    inline void read_dir(size_t  way,
568                         size_t  set,
569                         addr_t* tag,
570                         int*    state)
[297]571    {
572        *state = cache_state(way, set);
573        *tag   = cache_tag(way, set);
574    }
575
576    ////////////////////////////////////////////
[393]577    inline addr_t get_tag(size_t way, size_t set)
[297]578    {
579        return cache_tag(way, set);
580    }
581
582    ///////////////////////////////////////////////////////////////////
583    // This function writes a complete 32 bits word
584    // It does not use the directory and cannot miss.
585    //////////////////////////////////////////////////////////////////
[814]586    inline void write(size_t way,
587                      size_t set,
588                      size_t word,
[771]589                      data_t data)
[297]590    {
591        cache_data(way, set, word) = data;
592        cache_set_lru(way, set);
593    }
594
595    ////////////////////////////////////////////////////////////////////////////
596    // this function writes up to 4 bytes, taking into account the byte enable.
597    // It does not use the directory and cannot miss.
598    ////////////////////////////////////////////////////////////////////////////
[814]599    inline void write(size_t way,
600                      size_t set,
601                      size_t word,
602                      data_t data,
[771]603                      be_t   be)
[297]604    {
605        data_t mask = be2mask(be);
606        data_t prev = cache_data(way, set, word);
607        cache_data(way, set, word) = (mask & data) | (~mask & prev);
608        cache_set_lru(way, set);
609    }
610
611    //////////////////////////////////////////////////////////////////////////
612    // This function invalidates a cache line identified by the set and way.
613    // It returns true if the line was valid, and returns the line index.
614    //////////////////////////////////////////////////////////////////////////
[814]615    inline bool inval(size_t  way,
616                      size_t  set,
[771]617                      addr_t* nline)
[297]618    {
[823]619        if ((cache_state(way,set) == CACHE_SLOT_STATE_VALID_CC) or
620                (cache_state(way,set) == CACHE_SLOT_STATE_VALID_NCC))
[297]621        {
622            cache_state(way,set) = CACHE_SLOT_STATE_EMPTY;
[823]623            *nline = (data_t) cache_tag(way, set) * m_sets + set;
[297]624            return true;
625        }
626        return false;
627    }
628
629    //////////////////////////////////////////////////////////////////////////////////
630    // This function selects a victim slot in an associative set.
631    // It cannot fail, as a slot in ZOMBI state is considered EMPTY.
[814]632    // - we search first an EMPTY slot
[297]633    // - if no EMPTY slot, we search an OLD slot, using lru
[814]634    // It returns the line index (Z + Y fields), the selected slot way and set,
[297]635    // and a Boolean indicating that a cleanup is requested.
636    //////////////////////////////////////////////////////////////////////////////////
[814]637    inline bool victim_select(addr_t  ad,
638                              addr_t* victim,
639                              size_t* way,
[771]640                              size_t* set)
[297]641    {
[771]642        bool found   = false;
643        bool cleanup = false;
[297]644
645        *set = m_y[ad];
646        *way = 0;
647
[814]648        // Search first empty slot
[823]649        for (size_t _way = 0; _way < m_ways && !found; _way++)
[297]650        {
[823]651            // empty
652            if ((cache_state(_way, *set) != CACHE_SLOT_STATE_VALID_CC) and
653                    (cache_state(_way, *set) != CACHE_SLOT_STATE_VALID_NCC))
[297]654            {
655                found   = true;
656                cleanup = false;
657                *way    = _way;
658            }
659        }
660
[814]661        // If no empty slot, search first  old slot (lru == false)
[771]662        if (!found)
[814]663        {
[823]664            for (size_t _way = 0; _way < m_ways && !found; _way++)
[297]665            {
[771]666                if (not cache_lru(_way, *set))
[297]667                {
668                    found   = true;
669                    cleanup = true;
670                    *way    = _way;
671                }
672            }
673        }
674
675        assert(found && "all ways can't be new at the same time");
[823]676        *victim = (addr_t) ((cache_tag(*way, *set) * m_sets) + *set);
[297]677        return cleanup;
678    }
679
680    //////////////////////////////////////////////////////////////////////////////////
681    // This function selects a victim slot in an associative set.
682    // It can fail if all ways are in ZOMBI state.
683    // - we search first an EMPTY slot
684    // - if no empty slot, we search an OLD slot not in ZOMBI state,
685    // - if not found, we take the first not ZOMBI slot.
[814]686    // It returns the line index (Z + Y fields), the selected slot way and set,
[297]687    // and two Boolean indicating success and a required cleanup.
688    //////////////////////////////////////////////////////////////////////////////////
[814]689    inline void read_select(addr_t  ad,
690                            addr_t* victim,
691                            size_t* way,
[771]692                            size_t* set,
693                            bool*   found,
694                            bool*   cleanup)
[297]695    {
[303]696        size_t _set = m_y[ad];
697
698        *found = false;
699
[814]700        // Search first empty slot
[823]701        for (size_t _way = 0; _way < m_ways && !(*found); _way++)
[297]702        {
[771]703            if (cache_state(_way, _set) == CACHE_SLOT_STATE_EMPTY)
[297]704            {
705                *found   = true;
706                *cleanup = false;
707                *way     = _way;
708                *set     = m_y[ad];
709                return;
710            }
711        }
[814]712
713        // Search first not zombi old slot
[823]714        for (size_t _way = 0; _way < m_ways && !(*found); _way++)
[303]715        {
[814]716            if (not cache_lru(_way, _set) and
[823]717               (cache_state(_way, _set) != CACHE_SLOT_STATE_ZOMBI))
[297]718            {
[303]719                *found   = true;
720                *cleanup = true;
721                *way     = _way;
722                *set     = m_y[ad];
[393]723                *victim  = cache_tag(*way,_set) * m_sets + _set;
[303]724                return;
[297]725            }
726        }
727        // Search first not zombi slot
[823]728        for (size_t _way = 0; _way < m_ways && !(*found); _way++)
[303]729        {
[814]730            if (cache_state(_way, _set) != CACHE_SLOT_STATE_ZOMBI)
[297]731            {
[303]732                *found   = true;
733                *cleanup = true;
734                *way    = _way;
735                *set     = m_y[ad];
[393]736                *victim  = cache_tag(*way,_set) * m_sets + _set;
[303]737                return;
[297]738            }
739        }
740
741        // no slot found...
742        *found   = false;
743        *cleanup = false;
744    }
745
746    //////////////////////////////////////////////////////////////////
747    // This function update the directory part of a slot
748    // identified by the way & set.
749    //////////////////////////////////////////////////////////////////
[814]750    inline void victim_update_tag(addr_t ad,
751                                  size_t way,
[771]752                                  size_t set)
[297]753    {
[823]754        addr_t tag = m_z[ad];
[297]755
[823]756        cache_tag(way, set) = tag;
[477]757        cache_state(way, set) = CACHE_SLOT_STATE_VALID_CC;
[297]758        cache_set_lru(way, set);
759    }
760
761    //////////////////////////////////////////////////////////////////
762    // This function write the directory part of a slot
763    // identified by the way & set, when using the ZOMBI state.
764    //////////////////////////////////////////////////////////////////
[814]765    inline void write_dir(addr_t ad,
766                          size_t way,
[771]767                          size_t set,
768                          int    state)
[297]769    {
[771]770        addr_t tag = m_z[ad];
[297]771
[823]772        assert(((state == CACHE_SLOT_STATE_VALID_CC) or
773                (state == CACHE_SLOT_STATE_VALID_NCC) or
774                (state == CACHE_SLOT_STATE_ZOMBI) or
775                (state == CACHE_SLOT_STATE_EMPTY)) and
[297]776        "illegal slot state argument in Generic Cache write_dir()");
777
[823]778        assert((way < m_ways) and
[297]779        "too large way index argument in Generic Cache write_dir()");
780
[823]781        assert((set < m_sets) and
[297]782        "too large set index argument in Generic Cache write_dir()");
783
784        cache_tag(way, set)   = tag;
785        cache_state(way, set) = state;
786
[823]787        if ((state == CACHE_SLOT_STATE_VALID_CC) or (state == CACHE_SLOT_STATE_VALID_NCC))
788            cache_set_lru(way, set);
[297]789    }
790
[365]791    //////////////////////////////////////////////////////////////////
[393]792    // This function change the state of a slot
[365]793    // identified by the way & set, when using the ZOMBI state.
[393]794    // It does not affect the tag
[365]795    //////////////////////////////////////////////////////////////////
[814]796    inline void write_dir(size_t way,
[771]797                          size_t set,
798                          int    state)
[365]799    {
[823]800        assert(((state == CACHE_SLOT_STATE_VALID_CC) or
801                (state == CACHE_SLOT_STATE_VALID_NCC) or
802                (state == CACHE_SLOT_STATE_ZOMBI) or
803                (state == CACHE_SLOT_STATE_EMPTY) ) and
[365]804        "illegal slot state argument in Generic Cache write_dir()");
805
[823]806        assert((way < m_ways) and
[365]807        "too large way index argument in Generic Cache write_dir()");
808
[823]809        assert((set < m_sets) and
[365]810        "too large set index argument in Generic Cache write_dir()");
811
812        cache_state(way, set) = state;
813
[823]814        if ((state == CACHE_SLOT_STATE_VALID_CC) or (state == CACHE_SLOT_STATE_VALID_NCC))
815            cache_set_lru(way, set);
[365]816    }
817
[297]818    ///////////////////////////////////////////////////////////////////
819    // This function writes a full cache line in one single cycle.
820    // The target slot is identified by the way & set arguments.
821    // Both DATA and DIRECTORY are written
822    ///////////////////////////////////////////////////////////////////
[814]823    inline void update(addr_t  ad,
824                       size_t  way,
825                       size_t  set,
[771]826                       data_t* buf)
[297]827    {
[393]828        addr_t tag = m_z[ad];
[297]829
[823]830        cache_tag(way, set) = tag;
[477]831        cache_state(way, set) = CACHE_SLOT_STATE_VALID_CC;
[297]832        cache_set_lru(way, set);
[823]833        for (size_t word = 0; word < m_words; word++)
[297]834        {
[823]835            cache_data(way, set, word) = buf[word];
[297]836        }
837    }
838
839    ///////////////////////////
840    void fileTrace(FILE* file)
841    {
[823]842        for (size_t nway = 0; nway < m_ways; nway++)
[297]843        {
[823]844            for (size_t nset = 0; nset < m_sets; nset++)
[297]845            {
[823]846                fprintf(file, "%d / ", (int) cache_state(nway, nset));
847                fprintf(file, "way %d / ", (int) nway);
848                fprintf(file, "set %d / ", (int) nset);
[814]849                fprintf(file, "@ = %08zX / ",
[771]850                        ((cache_tag(nway, nset) * m_sets + nset) * m_words * 4));
[823]851                for (size_t nword = m_words; nword > 0; nword--)
[297]852                {
[771]853                    unsigned int data = cache_data(nway, nset, nword - 1);
854                    fprintf(file, "%08X ", data);
[297]855                }
856                fprintf(file, "\n");
857            }
858        }
859    }
860
861    ////////////////////////
862    inline void printTrace()
863    {
[823]864        for (size_t way = 0; way < m_ways; way++)
[297]865        {
[823]866            for (size_t set = 0; set < m_sets; set++)
[297]867            {
[823]868                addr_t addr = (((addr_t) cache_tag(way, set)) * m_words * m_sets + m_words * set) * 4;
[814]869                std::cout << std::dec << cache_state(way, set)
870                          << " | way " << way
871                          << " | set " << set
[393]872                          << std::hex << " | @ " << addr;
873
[823]874                for (size_t word = 0; word < m_words; word++)
[297]875                {
[823]876                    std::cout << " | " << cache_data(way, set, word) ;
[297]877                }
[477]878                std::cout << std::dec << std::endl ;
[297]879            }
880        }
881    }
[814]882
[297]883};
884
885} // namespace soclib
886
887#endif
888
889// Local Variables:
890// tab-width: 4
891// c-basic-offset: 4
892// c-file-offsets:((innamespace . 0)(inline-open . 0))
893// indent-tabs-mode: nil
894// End:
895
896// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
897
Note: See TracBrowser for help on using the repository browser.