source: branches/v4/lib/generic_cache_tsar/include/generic_cache.h @ 371

Last change on this file since 371 was 365, checked in by joannou, 12 years ago

In generic_cache_tsar, added a new write_dir function that does not affect the tag

File size: 36.1 KB
Line 
1/* -*- c++ -*-
2 *
3 * SOCLIB_LGPL_HEADER_BEGIN
4 *
5 * This file is part of SoCLib, GNU LGPLv2.1.
6 *
7 * SoCLib is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as published
9 * by the Free Software Foundation; version 2.1 of the License.
10 *
11 * SoCLib is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with SoCLib; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 * 02110-1301 USA
20 *
21 * SOCLIB_LGPL_HEADER_END
22 *
23 * Copyright (c) UPMC, Lip6
24 *         Alain Greiner <alain.greiner@lip6.fr> July 2008
25 *
26 * Maintainers: alain
27 */
28
29////////////////////////////////////////////////////////////////////////////////
30// File         : generic_cache.h
31// Date         : 07/01/2012
32// Authors      : Alain Greiner
33/////////////////////////////////////////////////////////////////////////////////
34// This object is a generic, set associative, cache.
35// Each slot can be in three states: VALID, EMPTY or ZOMBI.
36// The ZOMBI state is used by cache coherence protocoles 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// The address can be larger than 32 bits, but the TAG field
62// cannot be larger than 32 bits.
63/////////////////////////////////////////////////////////////////////////////////
64
65#ifndef SOCLIB_GENERIC_CACHE_H
66#define SOCLIB_GENERIC_CACHE_H
67
68#include <systemc>
69#include <cassert>
70#include "arithmetics.h"
71#include "static_assert.h"
72#include "mapping_table.h"
73#include <cstring>
74
75namespace soclib { 
76
77enum cache_slot_state_e
78{
79    CACHE_SLOT_STATE_EMPTY,
80    CACHE_SLOT_STATE_VALID,
81    CACHE_SLOT_STATE_ZOMBI,
82};
83
84//////////////////////////
85template<typename addr_t>
86class GenericCache
87//////////////////////////
88{
89    typedef uint32_t    data_t;
90    typedef uint32_t    tag_t;
91    typedef uint32_t    be_t;
92
93    data_t              *r_data ;
94    tag_t               *r_tag ;
95    int                 *r_state;
96    bool                *r_lru ;
97
98    size_t              m_ways; 
99    size_t              m_sets; 
100    size_t              m_words;
101
102    const soclib::common::AddressMaskingTable<addr_t>  m_x ;
103    const soclib::common::AddressMaskingTable<addr_t>  m_y ;
104    const soclib::common::AddressMaskingTable<addr_t>  m_z ;
105
106    //////////////////////////////////////////////////////////////
107    inline data_t &cache_data(size_t way, size_t set, size_t word)
108    {
109        return r_data[(way*m_sets*m_words)+(set*m_words)+word];
110    }
111
112    //////////////////////////////////////////////
113    inline tag_t &cache_tag(size_t way, size_t set)
114    {
115        return r_tag[(way*m_sets)+set];
116    }
117
118    //////////////////////////////////////////////
119    inline bool &cache_lru(size_t way, size_t set)
120    {
121        return r_lru[(way*m_sets)+set];
122    }
123
124    //////////////////////////////////////////////
125    inline int &cache_state(size_t way, size_t set)
126    {
127        return r_state[(way*m_sets)+set];
128    }
129
130    /////////////////////////////////////////////////
131    inline void cache_set_lru(size_t way, size_t set)
132    {
133            size_t way2;
134
135        cache_lru(way, set) = true;
136
137            for (way2 = 0; way2 < m_ways; way2++ ) 
138        {
139                if (cache_lru(way2, set) == false) return;
140            }
141            // all lines are new -> they all become old
142            for (way2 = 0; way2 < m_ways; way2++ ) 
143        {
144                cache_lru(way2, set) = false;
145            }
146    }
147
148    /////////////////////////////////////////////
149    inline data_t be2mask( be_t be )
150    {
151        data_t mask = 0;
152        if ( (be & 0x1) == 0x1 ) mask = mask | 0x000000FF;
153        if ( (be & 0x2) == 0x2 ) mask = mask | 0x0000FF00;
154        if ( (be & 0x4) == 0x4 ) mask = mask | 0x00FF0000;
155        if ( (be & 0x8) == 0x8 ) mask = mask | 0xFF000000;
156        return mask;
157    }
158
159public:
160
161    //////////////////////////////////////////////
162    GenericCache(   const std::string   &name,
163                    size_t              nways, 
164                    size_t              nsets, 
165                    size_t              nwords)
166        : m_ways(nways),
167          m_sets(nsets),
168          m_words(nwords),
169
170#define l2 soclib::common::uint32_log2
171
172          m_x( l2(nwords), l2(sizeof(data_t))),
173          m_y( l2(nsets), l2(nwords) + l2(sizeof(data_t))),
174          m_z( 8*sizeof(addr_t) - l2(nsets) - l2(nwords) - l2(sizeof(data_t)),
175               l2(nsets) + l2(nwords) + l2(sizeof(data_t)))
176#undef l2
177    {
178        assert(IS_POW_OF_2(nways));
179        assert(IS_POW_OF_2(nsets));
180        assert(IS_POW_OF_2(nwords));
181        assert(nwords);
182        assert(nsets);
183        assert(nways);
184        assert(nwords <= 64);
185        assert(nsets <= 1024);
186        assert(nways <= 16);
187
188#ifdef GENERIC_CACHE_DEBUG
189        std::cout
190            << " m_x: " << m_x
191            << " m_y: " << m_y
192            << " m_z: " << m_z
193            << std::endl;
194#endif
195
196        r_data    = new data_t[nways*nsets*nwords];
197        r_tag     = new tag_t[nways*nsets];
198        r_state   = new int[nways*nsets];
199        r_lru     = new bool[nways*nsets];
200    }
201
202    ////////////////
203    ~GenericCache()
204    {
205        delete [] r_data;
206        delete [] r_tag;
207        delete [] r_state;
208        delete [] r_lru;
209    }
210
211    ////////////////////
212    inline void reset( )
213    {
214        std::memset(r_data, 0, sizeof(*r_data)*m_ways*m_sets*m_words);
215        std::memset(r_tag, 0, sizeof(*r_tag)*m_ways*m_sets);
216        std::memset(r_state, CACHE_SLOT_STATE_EMPTY, sizeof(*r_state)*m_ways*m_sets);
217        std::memset(r_lru, 0, sizeof(*r_lru)*m_ways*m_sets);
218    }
219
220    /////////////////////////////////////////////////////////////////////
221    // Read a single 32 bits word.
222    // returns true if (matching tag) and (state == VALID)
223    // Both data & directory are accessed.
224    /////////////////////////////////////////////////////////////////////
225    inline bool read( addr_t    ad, 
226                      data_t*   dt)
227    {
228        const tag_t       tag  = m_z[ad];
229        const size_t      set  = m_y[ad];
230        const size_t      word = m_x[ad];
231
232        for ( size_t way = 0; way < m_ways; way++ ) 
233        {
234            if ( (tag == cache_tag(way, set)) 
235                   && (cache_state(way, set) == CACHE_SLOT_STATE_VALID) )
236            {
237                *dt = cache_data(way, set, word);
238                cache_set_lru(way, set);
239                return true;
240            }
241        }
242        return false;
243    }
244
245    ////////////////////////////////////////////////////////////////////
246    // Read a single 32 bits word.
247    // returns true if (matching tag) and (state == VALID)
248    // Both data & directory are accessed.
249    // The selected way, set and word index are returned in case of hit.
250    /////////////////////////////////////////////////////////////////////
251    inline bool read( addr_t    ad, 
252                      data_t*   dt,
253                      size_t*   selway,
254                      size_t*   selset,
255                      size_t*   selword) 
256    {
257        const tag_t       tag  = m_z[ad];
258        const size_t      set  = m_y[ad];
259        const size_t      word = m_x[ad];
260
261        for ( size_t way = 0; way < m_ways; way++ ) 
262        {
263            if ( (tag == cache_tag(way, set)) and
264                 (cache_state(way, set) == CACHE_SLOT_STATE_VALID) )
265            {
266                *selway  = way;
267                *selset  = set;
268                *selword = word;
269                *dt = cache_data(way, set, word);
270                cache_set_lru(way, set);
271                return true;
272            }
273        }
274        return false;
275    }
276
277    ////////////////////////////////////////////////////////////////////
278    // Read a single 32 bits word when the ZOMBI state is used.
279    // Both data and directory are accessed.
280    // returns the access status in the state argument:
281    // - VALID : (matching tag) and (state == VALID)
282    // - ZOMBI : (matching tag) and (state == ZOMBI)
283    // - MISS  : no matching tag or EMPTY state
284    // If VALID or ZOMBI, the data, the way, set and word index are
285    // returned in the other arguments.
286    ////////////////////////////////////////////////////////////////////
287    inline void read( addr_t    ad,
288                      data_t*   dt,
289                      size_t*   selway,
290                      size_t*   selset,
291                      size_t*   selword,
292                      int*      state ) 
293    {
294        const tag_t       tag  = m_z[ad];
295        const size_t      set  = m_y[ad];
296        const size_t      word = m_x[ad];
297
298        // default return values
299        *state   = CACHE_SLOT_STATE_EMPTY;
300        *selway  = 0;
301        *selset  = 0;
302        *selword = 0;
303        *dt      = 0;
304
305        for ( size_t way = 0; way < m_ways; way++ ) 
306        {
307            if ( tag == cache_tag(way, set) )  // matching tag
308            {
309
310                if ( cache_state(way, set) == CACHE_SLOT_STATE_VALID )
311                {
312                    *state   = CACHE_SLOT_STATE_VALID;
313                    *selway  = way;
314                    *selset  = set;
315                    *selword = word;
316                    *dt      = cache_data(way, set, word);
317                    cache_set_lru(way, set);
318                }
319                else if ( cache_state(way, set) == CACHE_SLOT_STATE_ZOMBI )
320                {
321                    *state   = CACHE_SLOT_STATE_ZOMBI;
322                    *selway  = way;
323                    *selset  = set;
324                    *selword = word;
325                }
326            }
327        }
328    }
329             
330    ////////////////////////////////////////////////////////////////////
331    // Read a single 32 bits word, without LRU update.
332    // returns true if (matching tag) and (state == VALID)
333    // Both data & directory are accessed.
334    // The selected way, set and word index are returned in case of hit.
335    /////////////////////////////////////////////////////////////////////
336    inline bool read_neutral( addr_t    ad, 
337                                      data_t*   dt,
338                                          size_t*   selway,
339                                          size_t*   selset,
340                                          size_t*   selword) 
341    {
342        const tag_t       tag  = m_z[ad];
343        const size_t      set  = m_y[ad];
344        const size_t      word = m_x[ad];
345
346        for ( size_t way = 0; way < m_ways; way++ ) 
347        {
348            if ( (tag == cache_tag(way, set)) 
349                   && (cache_state(way, set) == CACHE_SLOT_STATE_VALID) )
350            {
351                *selway  = way;
352                *selset  = set;
353                *selword = word;
354                *dt = cache_data(way, set, word);
355                return true;
356            }
357        }
358        return false;
359    }
360
361    /////////////////////////////////////////////////////////////////////////////
362    // Read one or two 32 bits word.
363    // Both data & directory are accessed.
364    // Hit if (matching tag) and (valid == true) and (zombi == false)
365    // If the addressed word is not the last in the cache line,
366    // two successive words are returned.
367    // The selected way, set and first word index are returned in case of hit.
368    // This function is used by the cc_vcache to get a 64 bits page table entry.
369    /////////////////////////////////////////////////////////////////////////////
370    inline bool read( addr_t    ad, 
371                      data_t*   dt, 
372                      data_t*   dt_next,
373                      size_t*   selway,
374                      size_t*   selset,
375                      size_t*   selword)
376    {
377        const tag_t       tag  = m_z[ad];
378        const size_t      set  = m_y[ad];
379        const size_t      word = m_x[ad];
380
381        for ( size_t way = 0; way < m_ways; way++ ) 
382        {
383            if ( (tag == cache_tag(way, set))   
384                   && (cache_state(way, set) == CACHE_SLOT_STATE_VALID) ) 
385            {
386                *dt      = cache_data(way, set, word);
387                if ( word+1 < m_words) 
388                {
389                    *dt_next = cache_data(way, set, word+1);
390                }
391                *selway  = way;
392                *selset  = set;
393                *selword = word;
394                cache_set_lru(way, set);
395                return true;
396            }
397        }
398        return false;
399    }
400
401    ////////////////////////////////////////////////////////////////////
402    // Read one or two 32 bits word.
403    // Both data and directory are accessed.
404    // returns the access status in the state argument:
405    // - VALID : (matching tag) and (state == VALID)
406    // - ZOMBI : (matching tag) and (state == ZOMBI)
407    // - MISS  : no matching tag or EMPTY state
408    // If VALID or ZOMBI, the data, the way, set and word index are
409    // returned in the other arguments.
410    ////////////////////////////////////////////////////////////////////
411    inline void read( addr_t    ad,
412                      data_t*   dt,
413                      data_t*   dt_next,
414                      size_t*   selway,
415                      size_t*   selset,
416                      size_t*   selword,
417                      int*      state ) 
418    {
419        const tag_t       tag  = m_z[ad];
420        const size_t      set  = m_y[ad];
421        const size_t      word = m_x[ad];
422
423        // default return values
424        *state   = CACHE_SLOT_STATE_EMPTY;
425        *selway  = 0;
426        *selset  = 0;
427        *selword = 0;
428        *dt      = 0;
429
430        for ( size_t way = 0; way < m_ways; way++ ) 
431        {
432            if ( tag == cache_tag(way, set) )  // matching tag
433            {
434
435                if ( cache_state(way, set) == CACHE_SLOT_STATE_VALID )
436                {
437                    *state   = CACHE_SLOT_STATE_VALID;