OSDN Git Service

Enable to track git://github.com/monaka/binutils.git
[pf3gnuchains/pf3gnuchains3x.git] / sid / component / cache / mep-cache.cxx
1 // mep-cache.cxx - An implementation of the Cache for the
2 // Toshiba Media Processor (MeP). -*- C++ -*-
3
4 // Copyright (C) 2004, 2005 Red Hat.
5 // This file is part of SID and is licensed under the GPL.
6 // See the file COPYING.SID for conditions for redistribution.
7
8 #include "config.h"
9
10 #include <sidcomp.h>
11 #include <sidso.h>
12 #include <sidcomputil.h>
13 #include <sidattrutil.h>
14 #include <sidpinutil.h>
15 #include <sidbusutil.h>
16 #include <sidmiscutil.h>
17 #include <sidtypes.h>
18
19 #include <stdlib.h>
20 #include <vector>
21 #include <string>
22 #include <iostream>
23
24 #include "mep-cache.h"
25
26 using namespace sid;
27 using namespace sidutil;
28 using std::setw;
29 using std::setfill;
30 using std::cerr;
31
32 mep_cache::mep_cache (unsigned assoc, unsigned cache_sz, unsigned line_sz,
33                       cache_replacement_algorithm& replacer)
34   : blocking_cache_component (this, assoc, cache_sz, line_sz, replacer, *(new mep_cache_line_factory (*this))),
35     tag_test_mem (0),
36     data_test_mem (0),
37     clear_tag_pin (this, & mep_cache::clear_tag),
38     endian_set_pin (this, & mep_cache::endian_set_pin_handler)
39 {
40   add_accessor ("tag-test-mem", &tag_test_mem);
41   add_accessor ("data-test-mem", &data_test_mem);
42   add_pin ("clear-tag", &clear_tag_pin);
43   add_pin ("endian-set!", & this->endian_set_pin);
44   add_attribute ("endian", &endianness);
45 }
46
47 void
48 mep_cache::endian_set_pin_handler(sid::host_int_4 v)
49 {
50   switch (v)
51     {
52     case 1:
53       this->endianness = endian_big;
54       break;
55     case 2:
56       this->endianness = endian_little;
57       break;
58     default:
59       // XXX: warning message?
60       break;
61     }
62 }
63
64 void
65 mep_cache::write_tag (unsigned way, int index, cache_tag atag)
66 {
67   if (! tag_test_mem)
68     return;
69
70   host_int_4 address = (way * cache_size / 2) + (index * line_size);
71   if (endianness == endian_big)
72     {
73       big_int_4 data = atag;
74       tag_test_mem->write (address, data);
75     }
76   else
77     {
78       little_int_4 data = atag;
79       tag_test_mem->write (address, data);
80     }
81 }
82
83 cache_tag
84 mep_cache::read_tag (unsigned way, int index)
85 {
86   if (! tag_test_mem)
87     return 0;
88
89   host_int_4 address = (way * cache_size / 2) + (index * line_size);
90   if (endianness == endian_big)
91     {
92       big_int_4 atag;
93       tag_test_mem->read (address, atag);
94       return atag;
95     }
96   little_int_4 atag;
97   tag_test_mem->read (address, atag);
98   return atag;
99 }
100
101 #define DEFN_METHOD(DataType) \
102 /* Insert a datum into the line at the given index, starting at byte offset.  */ \
103 void \
104 mep_cache::write_data (unsigned way, int index, unsigned offset, DataType new_data) \
105 { \
106   if (! data_test_mem) \
107     return; \
108   host_int_4 address = (way * cache_size / 2) + (index * line_size) + offset; \
109   data_test_mem->write (address, new_data); \
110 }\
111 /* Extract a datum from the line at the given index, starting at byte offset.  */ \
112 void \
113 mep_cache::read_data (unsigned way, int index, unsigned offset, DataType& new_data) const \
114 { \
115   if (! data_test_mem) \
116     return; \
117   host_int_4 address = (way * cache_size / 2) + (index * line_size) + offset; \
118   data_test_mem->read (address, new_data); \
119 }
120
121 DEFN_METHOD (sid::big_int_1)
122 DEFN_METHOD (sid::big_int_2)
123 DEFN_METHOD (sid::big_int_4)
124 DEFN_METHOD (sid::big_int_8)
125 DEFN_METHOD (sid::little_int_1)
126 DEFN_METHOD (sid::little_int_2)
127 DEFN_METHOD (sid::little_int_4)
128 DEFN_METHOD (sid::little_int_8)
129 #undef DEFN_METHOD
130
131 void
132 mep_cache::clear_tag (host_int_4 addr)
133 {
134   cache_tag tag = acache.addr_to_tag (addr);
135   cache_line* line = acache.find (tag);
136   if (line && line->valid_p ())
137     {
138       mep_cache_line *mep_line = dynamic_cast<mep_cache_line*> (line);
139       assert (mep_line);
140       mep_line->clear_tag ();
141     }
142 }
143
144 void
145 mep_cache::dump_data (unsigned way, int index) const
146 {
147   for (unsigned i = 0; i < line_size; i++)
148     {
149       sid::little_int_1 data;
150       read_data (way, index, i, data);
151       cerr << setw (2) << setfill ('0') << static_cast<unsigned> (data);
152     }
153 }
154
155 void
156 mep_cache::configure (const string &config)
157 {
158   // Call up to the base class first
159   blocking_cache_component::configure (config);
160
161   // Now handle relevent configuration for us.
162   if (config.size () <= 13)
163     return;
164   if (config.substr (0, 13) == "model-busses=")
165     {
166       set_attribute_value ("blockable?", config.substr (13));
167       return;
168     }
169 }
170
171 // ----------------------------------------
172
173 mep_cache_line::mep_cache_line (unsigned line_size, unsigned index, unsigned way, mep_cache &c) :
174   my_size (line_size),
175   my_way (way),
176   my_index (index),
177   my_cache (c)
178 {
179   // Compute a shift amount for removing the index from an address.
180   index_shift = log2 (my_size);
181
182   // Compute a mask for extracting the tag index
183   unsigned assoc = my_cache.assoc ();
184   unsigned size = my_cache.size ();
185   unsigned indices = size / assoc / line_size;
186   index_mask = (1 << log2 (indices)) - 1;
187
188   // Compute a mask for extracting the address tag.
189   int non_address_bits = log2 (size) - log2 (assoc);
190   address_mask = ~((1 << non_address_bits) - 1);
191 }
192
193 // Get the line's tag.
194 void
195 mep_cache_line::set_raw_tag (cache_tag atag)
196 {
197   // Tag is already shifted to the index.
198   assert (my_index == ((atag >> index_shift) & index_mask));
199   my_cache.write_tag (my_way, my_index, atag);
200 }
201
202 void
203 mep_cache_line::set_tag (cache_tag atag)
204 {
205   // Tag is already shifted to the index.
206   assert (my_index == (atag & index_mask));
207   atag <<= index_shift;
208
209   cache_tag oldtag = raw_tag ();
210   oldtag &= ~address_mask;
211   oldtag |= atag & address_mask;
212   my_cache.write_tag (my_way, my_index, oldtag);
213 }
214
215 void
216 mep_cache_line::clear_tag ()
217 {
218   // Clear the tag bits as well as the dirty and valid bits.
219   // Leave the R bit intact.
220   cache_tag oldtag = raw_tag ();
221   oldtag &= 0x4;
222   my_cache.write_tag (my_way, my_index, oldtag);
223 }
224
225 cache_tag
226 mep_cache_line::raw_tag () const
227 {
228   assert (my_index >= 0);
229   cache_tag atag = my_cache.read_tag (my_way, my_index);
230   // Add the index back into the tag
231   atag |= my_index << index_shift;
232   return atag;
233 }
234
235 cache_tag
236 mep_cache_line::tag () const
237 {
238   return raw_tag () >> index_shift;
239 }
240
241 // Mark the line dirty or clean.
242 void
243 mep_cache_line::dirty ()
244 {
245   assert (my_index >= 0);
246   cache_tag atag = raw_tag ();
247   atag |= 0x2;
248   set_raw_tag (atag);
249 }
250
251 void
252 mep_cache_line::clean ()
253 {
254   assert (my_index >= 0);
255   cache_tag atag = raw_tag ();
256   atag &= ~0x2;
257   set_raw_tag (atag);
258 }
259
260 // Mark the line valid or invalid.
261 void
262 mep_cache_line::validate ()
263 {
264   assert (my_index >= 0);
265   cache_tag atag = raw_tag ();
266   atag |= 0x1;
267   set_raw_tag (atag);
268 }
269
270 void
271 mep_cache_line::invalidate ()
272 {
273   assert (my_index >= 0);
274   cache_tag atag = raw_tag ();
275   atag &= ~0x1;
276   set_raw_tag (atag);
277 }
278
279 // Maintain the R bit
280 int
281 mep_cache_line::get_R () const
282 {
283   assert (my_index >= 0);
284   cache_tag atag = raw_tag ();
285   return (atag >> 2) & 0x1;
286 }
287
288 void
289 mep_cache_line::set_R (int R)
290 {
291   assert (my_index >= 0);
292   cache_tag atag = raw_tag ();
293   atag &= ~0x4;
294   atag |= (R & 0x1) << 2;
295   set_raw_tag (atag);
296 }
297
298 // Lock or unlock the line.
299 void
300 mep_cache_line::lock ()
301 {
302   // Nothing to do
303 }
304
305 void
306 mep_cache_line::unlock ()
307 {
308   // Nothing to do
309 }
310
311 // Is the line dirty?
312 bool
313 mep_cache_line::dirty_p () const
314 {
315   assert (my_index >= 0);
316   cache_tag atag = raw_tag ();
317   return (atag & 0x2) != 0;
318 }
319
320 // Is the line valid?
321 bool
322 mep_cache_line::valid_p () const
323 {
324   assert (my_index >= 0);
325   cache_tag atag = raw_tag ();
326   return (atag & 0x1) != 0;
327 }
328
329 // Is the line locked?
330 bool
331 mep_cache_line::locked_p () const
332 {
333   return false; // Lines can't be locked
334 }
335
336 #define DEFN_METHOD(DataType) \
337 /* Insert a datum into the line, starting at byte offset.  */ \
338 void \
339 mep_cache_line::insert (unsigned offset, DataType new_data) \
340 { \
341   assert (offset + sizeof (new_data) <= my_size); \
342   assert (my_index >= 0); \
343   my_cache.write_data (my_way, my_index, offset, new_data); \
344   dirty (); \
345 } \
346 /* Extract a datum from the line, starting at byte offset.  */ \
347 void \
348 mep_cache_line::extract (unsigned offset, DataType& new_data) const \
349 { \
350   assert (offset + sizeof (new_data) <= my_size); \
351   assert (my_index >= 0); \
352   my_cache.read_data (my_way, my_index, offset, new_data); \
353 }
354
355 DEFN_METHOD (sid::big_int_1)
356 DEFN_METHOD (sid::big_int_2)
357 DEFN_METHOD (sid::big_int_4)
358 DEFN_METHOD (sid::big_int_8)
359 DEFN_METHOD (sid::little_int_1)
360 DEFN_METHOD (sid::little_int_2)
361 DEFN_METHOD (sid::little_int_4)
362 DEFN_METHOD (sid::little_int_8)
363 #undef DEFN_METHOD
364
365 // Dump a line in human readable form to cout.
366 void
367 mep_cache_line::dump_data () const
368 {
369   assert (my_index >= 0);
370   my_cache.dump_data (my_way, my_index);
371 }
372
373 // ----------------------------------------
374
375 // Choose a line to replace in a cache set. Return it, if successful
376 cache_line *
377 mep_assoc_replacement_algorithm::expell (cache_set &set)
378 {
379   // Check the R bit in way 0 for the index of the line to be replaced.
380   cache_line *line = &set[0];
381   mep_cache_line *mep_line = dynamic_cast<mep_cache_line*> (line);
382   assert (mep_line);
383   int R = mep_line->get_R ();
384   assert (R == 0 || R == 1);
385
386   // Reset the bit so the other line is replaced next time.
387   mep_line->set_R (! R);
388
389   return &set[R];
390 }