* dcache.c (dcache_info): Output a cache line's state vector so it
[external/binutils.git] / gdb / dcache.c
1 /* Caching code.  Typically used by remote back ends for
2    caching remote memory.
3
4    Copyright 1992-1993, 1995, 1998-1999 Free Software Foundation, Inc.
5
6    This file is part of GDB.
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 59 Temple Place - Suite 330,
21    Boston, MA 02111-1307, USA.  */
22
23 #include "defs.h"
24 #include "dcache.h"
25 #include "gdbcmd.h"
26 #include "gdb_string.h"
27 #include "gdbcore.h"
28
29 /* 
30    The data cache could lead to incorrect results because it doesn't know
31    about volatile variables, thus making it impossible to debug
32    functions which use memory mapped I/O devices.
33
34    set remotecache 0
35
36    In those cases.
37
38    In general the dcache speeds up performance, some speed improvement
39    comes from the actual caching mechanism, but the major gain is in
40    the reduction of the remote protocol overhead; instead of reading
41    or writing a large area of memory in 4 byte requests, the cache
42    bundles up the requests into 32 byte (actually LINE_SIZE) chunks.
43    Reducing the overhead to an eighth of what it was.  This is very
44    obvious when displaying a large amount of data,
45
46    eg, x/200x 0 
47
48    caching     |   no    yes 
49    ---------------------------- 
50    first time  |   4 sec  2 sec improvement due to chunking 
51    second time |   4 sec  0 sec improvement due to caching
52
53    The cache structure is unusual, we keep a number of cache blocks
54    (DCACHE_SIZE) and each one caches a LINE_SIZEed area of memory.
55    Within each line we remember the address of the line (always a
56    multiple of the LINE_SIZE) and a vector of bytes over the range.
57    There's another vector which contains the state of the bytes.
58
59    ENTRY_BAD means that the byte is just plain wrong, and has no
60    correspondence with anything else (as it would when the cache is
61    turned on, but nothing has been done to it.
62
63    ENTRY_DIRTY means that the byte has some data in it which should be
64    written out to the remote target one day, but contains correct
65    data.  ENTRY_OK means that the data is the same in the cache as it
66    is in remote memory.
67
68
69    The ENTRY_DIRTY state is necessary because GDB likes to write large
70    lumps of memory in small bits.  If the caching mechanism didn't
71    maintain the DIRTY information, then something like a two byte
72    write would mean that the entire cache line would have to be read,
73    the two bytes modified and then written out again.  The alternative
74    would be to not read in the cache line in the first place, and just
75    write the two bytes directly into target memory.  The trouble with
76    that is that it really nails performance, because of the remote
77    protocol overhead.  This way, all those little writes are bundled
78    up into an entire cache line write in one go, without having to
79    read the cache line in the first place.
80
81
82  */
83
84
85 /* This value regulates the number of cache blocks stored.
86    Smaller values reduce the time spent searching for a cache
87    line, and reduce memory requirements, but increase the risk
88    of a line not being in memory */
89
90 #define DCACHE_SIZE 64
91
92 /* This value regulates the size of a cache line.  Smaller values
93    reduce the time taken to read a single byte, but reduce overall
94    throughput.  */
95
96 #define LINE_SIZE_POWER (5)
97 #define LINE_SIZE (1 << LINE_SIZE_POWER)
98
99 /* Each cache block holds LINE_SIZE bytes of data
100    starting at a multiple-of-LINE_SIZE address.  */
101
102 #define LINE_SIZE_MASK  ((LINE_SIZE - 1))
103 #define XFORM(x)        ((x) & LINE_SIZE_MASK)
104 #define MASK(x)         ((x) & ~LINE_SIZE_MASK)
105
106
107 #define ENTRY_BAD   0           /* data at this byte is wrong */
108 #define ENTRY_DIRTY 1           /* data at this byte needs to be written back */
109 #define ENTRY_OK    2           /* data at this byte is same as in memory */
110
111
112 struct dcache_block
113   {
114     struct dcache_block *p;     /* next in list */
115     CORE_ADDR addr;             /* Address for which data is recorded.  */
116     char data[LINE_SIZE];       /* bytes at given address */
117     unsigned char state[LINE_SIZE];     /* what state the data is in */
118
119     /* whether anything in state is dirty - used to speed up the 
120        dirty scan. */
121     int anydirty;
122
123     int refs;
124   };
125
126
127 struct dcache_struct
128   {
129     /* Function to actually read the target memory. */
130     memxferfunc read_memory;
131
132     /* Function to actually write the target memory */
133     memxferfunc write_memory;
134
135     /* free list */
136     struct dcache_block *free_head;
137     struct dcache_block *free_tail;
138
139     /* in use list */
140     struct dcache_block *valid_head;
141     struct dcache_block *valid_tail;
142
143     /* The cache itself. */
144     struct dcache_block *the_cache;
145
146     /* potentially, if the cache was enabled, and then turned off, and
147        then turned on again, the stuff in it could be stale, so this is
148        used to mark it */
149     int cache_has_stuff;
150   };
151
152 static int dcache_poke_byte (DCACHE *dcache, CORE_ADDR addr, char *ptr);
153
154 static int dcache_peek_byte (DCACHE *dcache, CORE_ADDR addr, char *ptr);
155
156 static struct dcache_block *dcache_hit (DCACHE *dcache, CORE_ADDR addr);
157
158 static int dcache_write_line (DCACHE *dcache, struct dcache_block *db);
159
160 static int dcache_read_line (DCACHE *dcache, struct dcache_block *db);
161
162 static struct dcache_block *dcache_alloc (DCACHE *dcache, CORE_ADDR addr);
163
164 static int dcache_writeback (DCACHE *dcache);
165
166 static void dcache_info (char *exp, int tty);
167
168 void _initialize_dcache (void);
169
170 static int dcache_enabled_p = 0;
171
172 DCACHE *last_cache;             /* Used by info dcache */
173
174
175 /* Free all the data cache blocks, thus discarding all cached data.  */
176
177 void
178 dcache_invd (DCACHE *dcache)
179 {
180   int i;
181   dcache->valid_head = 0;
182   dcache->valid_tail = 0;
183
184   dcache->free_head = 0;
185   dcache->free_tail = 0;
186
187   for (i = 0; i < DCACHE_SIZE; i++)
188     {
189       struct dcache_block *db = dcache->the_cache + i;
190
191       if (!dcache->free_head)
192         dcache->free_head = db;
193       else
194         dcache->free_tail->p = db;
195       dcache->free_tail = db;
196       db->p = 0;
197     }
198
199   dcache->cache_has_stuff = 0;
200
201   return;
202 }
203
204 /* If addr is present in the dcache, return the address of the block
205    containing it. */
206
207 static struct dcache_block *
208 dcache_hit (DCACHE *dcache, CORE_ADDR addr)
209 {
210   register struct dcache_block *db;
211
212   /* Search all cache blocks for one that is at this address.  */
213   db = dcache->valid_head;
214
215   while (db)
216     {
217       if (MASK (addr) == db->addr)
218         {
219           db->refs++;
220           return db;
221         }
222       db = db->p;
223     }
224
225   return NULL;
226 }
227
228 /* Make sure that anything in this line which needs to
229    be written is. */
230
231 static int
232 dcache_write_line (DCACHE *dcache, register struct dcache_block *db)
233 {
234   int s;
235   int e;
236
237   if (db->anydirty)
238     {
239       for (s = 0; s < LINE_SIZE; s++)
240         {
241           if (db->state[s] == ENTRY_DIRTY)
242             {
243               int len = 0;
244               for (e = s; e < LINE_SIZE; e++, len++)
245                 if (db->state[e] != ENTRY_DIRTY)
246                   break;
247               {
248                 /* all bytes from s..s+len-1 need to
249                    be written out */
250                 int done = 0;
251                 while (done < len)
252                   {
253                     int t = dcache->write_memory (db->addr + s + done,
254                                                   db->data + s + done,
255                                                   len - done);
256                     if (t == 0)
257                       return 0;
258                     done += t;
259                   }
260                 memset (db->state + s, ENTRY_OK, len);
261                 s = e;
262               }
263             }
264         }
265       db->anydirty = 0;
266     }
267   return 1;
268 }
269
270
271 /* Read cache line */
272 static int
273 dcache_read_line (DCACHE *dcache, struct dcache_block *db)
274 {
275   CORE_ADDR memaddr;
276   char *myaddr;
277   int len;
278   int res;
279
280   /* If there are any dirty bytes in the line, it must be written
281      before a new line can be read */
282   if (db->anydirty)
283     {
284       if (!dcache_write_line (dcache, db))
285         return 0;
286     }
287   
288   len = LINE_SIZE;
289   memaddr = db->addr;
290   myaddr  = db->data;
291
292   while (len > 0)
293     {
294       res = (*dcache->read_memory) (memaddr, myaddr, len);
295       if (res == 0)
296         return 0;
297
298       memaddr += res;
299       myaddr  += res;
300       len     -= res;
301     }
302
303   memset (db->state, ENTRY_OK, sizeof (db->data));
304   db->anydirty = 0;
305   
306   return 1;
307 }
308
309 /* Get a free cache block, put or keep it on the valid list,
310    and return its address.  */
311
312 static struct dcache_block *
313 dcache_alloc (DCACHE *dcache, CORE_ADDR addr)
314 {
315   register struct dcache_block *db;
316
317   if (dcache_enabled_p == 0)
318     abort ();
319
320   /* Take something from the free list */
321   db = dcache->free_head;
322   if (db)
323     {
324       dcache->free_head = db->p;
325     }
326   else
327     {
328       /* Nothing left on free list, so grab one from the valid list */
329       db = dcache->valid_head;
330
331       if (!dcache_write_line (dcache, db))
332         return NULL;
333       
334       dcache->valid_head = db->p;
335     }
336
337   db->addr = MASK(addr);
338   db->refs = 0;
339   db->anydirty = 0;
340   memset (db->state, ENTRY_BAD, sizeof (db->data));
341
342   /* append this line to end of valid list */
343   if (!dcache->valid_head)
344     dcache->valid_head = db;
345   else
346     dcache->valid_tail->p = db;
347   dcache->valid_tail = db;
348   db->p = 0;
349
350   return db;
351 }
352
353 /* Writeback any dirty lines to the remote. */
354 static int
355 dcache_writeback (DCACHE *dcache)
356 {
357   struct dcache_block *db;
358
359   db = dcache->valid_head;
360
361   while (db)
362     {
363       if (!dcache_write_line (dcache, db))
364         return 0;
365       db = db->p;
366     }
367   return 1;
368 }
369
370
371 /* Using the data cache DCACHE return the contents of the byte at
372    address ADDR in the remote machine.  
373
374    Returns 0 on error. */
375
376 static int
377 dcache_peek_byte (DCACHE *dcache, CORE_ADDR addr, char *ptr)
378 {
379   register struct dcache_block *db = dcache_hit (dcache, addr);
380
381   if (!db)
382     {
383       db = dcache_alloc (dcache, addr);
384       if (!db)
385         return 0;
386     }
387   
388   if (db->state[XFORM (addr)] == ENTRY_BAD)
389     {
390       if (!dcache_read_line(dcache, db))
391          return 0;
392     }
393
394   *ptr = db->data[XFORM (addr)];
395   return 1;
396 }
397
398
399 /* Write the byte at PTR into ADDR in the data cache.
400    Return zero on write error.
401  */
402
403 static int
404 dcache_poke_byte (DCACHE *dcache, CORE_ADDR addr, char *ptr)
405 {
406   register struct dcache_block *db = dcache_hit (dcache, addr);
407
408   if (!db)
409     {
410       db = dcache_alloc (dcache, addr);
411       if (!db)
412         return 0;
413     }
414
415   db->data[XFORM (addr)] = *ptr;
416   db->state[XFORM (addr)] = ENTRY_DIRTY;
417   db->anydirty = 1;
418   return 1;
419 }
420
421 /* Initialize the data cache.  */
422 DCACHE *
423 dcache_init (memxferfunc reading, memxferfunc writing)
424 {
425   int csize = sizeof (struct dcache_block) * DCACHE_SIZE;
426   DCACHE *dcache;
427
428   dcache = (DCACHE *) xmalloc (sizeof (*dcache));
429   dcache->read_memory = reading;
430   dcache->write_memory = writing;
431
432   dcache->the_cache = (struct dcache_block *) xmalloc (csize);
433   memset (dcache->the_cache, 0, csize);
434
435   dcache_invd (dcache);
436
437   last_cache = dcache;
438   return dcache;
439 }
440
441 /* Free a data cache */
442 void
443 dcache_free (DCACHE *dcache)
444 {
445   if (last_cache == dcache)
446     last_cache = NULL;
447
448   free (dcache->the_cache);
449   free (dcache);
450 }
451
452 /* Read or write LEN bytes from inferior memory at MEMADDR, transferring
453    to or from debugger address MYADDR.  Write to inferior if SHOULD_WRITE is
454    nonzero. 
455
456    Returns length of data written or read; 0 for error.  
457
458    This routine is indended to be called by remote_xfer_ functions. */
459
460 int
461 dcache_xfer_memory (DCACHE *dcache, CORE_ADDR memaddr, char *myaddr, int len,
462                     int should_write)
463 {
464   int i;
465
466   if (dcache_enabled_p)
467     {
468       int (*xfunc) (DCACHE *dcache, CORE_ADDR addr, char *ptr);
469       xfunc = should_write ? dcache_poke_byte : dcache_peek_byte;
470
471       for (i = 0; i < len; i++)
472         {
473           if (!xfunc (dcache, memaddr + i, myaddr + i))
474             return 0;
475         }
476
477       if (should_write)
478         dcache_writeback (dcache);
479
480       dcache->cache_has_stuff = 1;
481     }
482   else
483     {
484       memxferfunc xfunc;
485       xfunc = should_write ? dcache->write_memory : dcache->read_memory;
486
487       if (dcache->cache_has_stuff)
488         dcache_invd (dcache);
489
490       len = xfunc (memaddr, myaddr, len);
491     }
492   return len;
493 }
494
495 static void
496 dcache_info (char *exp, int tty)
497 {
498   struct dcache_block *p;
499
500   if (!dcache_enabled_p)
501     {
502       printf_filtered ("Dcache not enabled\n");
503       return;
504     }
505   printf_filtered ("Dcache enabled, line width %d, depth %d\n",
506                    LINE_SIZE, DCACHE_SIZE);
507
508   if (last_cache)
509     {
510       printf_filtered ("Cache state:\n");
511
512       for (p = last_cache->valid_head; p; p = p->p)
513         {
514           int j;
515           printf_filtered ("Line at %s, referenced %d times\n",
516                            paddr (p->addr), p->refs);
517
518           for (j = 0; j < LINE_SIZE; j++)
519             printf_filtered ("%02x", p->data[j] & 0xFF);
520           printf_filtered ("\n");
521
522           for (j = 0; j < LINE_SIZE; j++)
523             printf_filtered ("%2x", p->state[j]);
524           printf_filtered ("\n");
525         }
526     }
527 }
528
529 /* Turn dcache on or off. */
530 void
531 set_dcache_state (int what)
532 {
533   dcache_enabled_p = !!what;
534 }
535
536 void
537 _initialize_dcache (void)
538 {
539   add_show_from_set
540     (add_set_cmd ("remotecache", class_support, var_boolean,
541                   (char *) &dcache_enabled_p,
542                   "\
543 Set cache use for remote targets.\n\
544 When on, use data caching for remote targets.  For many remote targets\n\
545 this option can offer better throughput for reading target memory.\n\
546 Unfortunately, gdb does not currently know anything about volatile\n\
547 registers and thus data caching will produce incorrect results with\n\
548 volatile registers are in use.  By default, this option is off.",
549                   &setlist),
550      &showlist);
551
552   add_info ("dcache", dcache_info,
553             "Print information on the dcache performance.");
554
555 }