GDB (API)
/home/stan/gdb/src/gdb/dcache.c
Go to the documentation of this file.
00001 /* Caching code for GDB, the GNU debugger.
00002 
00003    Copyright (C) 1992-2013 Free Software Foundation, Inc.
00004 
00005    This file is part of GDB.
00006 
00007    This program is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU General Public License as published by
00009    the Free Software Foundation; either version 3 of the License, or
00010    (at your option) any later version.
00011 
00012    This program is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015    GNU General Public License for more details.
00016 
00017    You should have received a copy of the GNU General Public License
00018    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
00019 
00020 #include "defs.h"
00021 #include "dcache.h"
00022 #include "gdbcmd.h"
00023 #include "gdb_string.h"
00024 #include "gdbcore.h"
00025 #include "target.h"
00026 #include "inferior.h"
00027 #include "splay-tree.h"
00028 
00029 /* Commands with a prefix of `{set,show} dcache'.  */
00030 static struct cmd_list_element *dcache_set_list = NULL;
00031 static struct cmd_list_element *dcache_show_list = NULL;
00032 
00033 /* The data cache could lead to incorrect results because it doesn't
00034    know about volatile variables, thus making it impossible to debug
00035    functions which use memory mapped I/O devices.  Set the nocache
00036    memory region attribute in those cases.
00037 
00038    In general the dcache speeds up performance.  Some speed improvement
00039    comes from the actual caching mechanism, but the major gain is in
00040    the reduction of the remote protocol overhead; instead of reading
00041    or writing a large area of memory in 4 byte requests, the cache
00042    bundles up the requests into LINE_SIZE chunks, reducing overhead
00043    significantly.  This is most useful when accessing a large amount
00044    of data, such as when performing a backtrace.
00045 
00046    The cache is a splay tree along with a linked list for replacement.
00047    Each block caches a LINE_SIZE area of memory.  Within each line we
00048    remember the address of the line (which must be a multiple of
00049    LINE_SIZE) and the actual data block.
00050 
00051    Lines are only allocated as needed, so DCACHE_SIZE really specifies the
00052    *maximum* number of lines in the cache.
00053 
00054    At present, the cache is write-through rather than writeback: as soon
00055    as data is written to the cache, it is also immediately written to
00056    the target.  Therefore, cache lines are never "dirty".  Whether a given
00057    line is valid or not depends on where it is stored in the dcache_struct;
00058    there is no per-block valid flag.  */
00059 
00060 /* NOTE: Interaction of dcache and memory region attributes
00061 
00062    As there is no requirement that memory region attributes be aligned
00063    to or be a multiple of the dcache page size, dcache_read_line() and
00064    dcache_write_line() must break up the page by memory region.  If a
00065    chunk does not have the cache attribute set, an invalid memory type
00066    is set, etc., then the chunk is skipped.  Those chunks are handled
00067    in target_xfer_memory() (or target_xfer_memory_partial()).
00068 
00069    This doesn't occur very often.  The most common occurance is when
00070    the last bit of the .text segment and the first bit of the .data
00071    segment fall within the same dcache page with a ro/cacheable memory
00072    region defined for the .text segment and a rw/non-cacheable memory
00073    region defined for the .data segment.  */
00074 
00075 /* The maximum number of lines stored.  The total size of the cache is
00076    equal to DCACHE_SIZE times LINE_SIZE.  */
00077 #define DCACHE_DEFAULT_SIZE 4096
00078 static unsigned dcache_size = DCACHE_DEFAULT_SIZE;
00079 
00080 /* The default size of a cache line.  Smaller values reduce the time taken to
00081    read a single byte and make the cache more granular, but increase
00082    overhead and reduce the effectiveness of the cache as a prefetcher.  */
00083 #define DCACHE_DEFAULT_LINE_SIZE 64
00084 static unsigned dcache_line_size = DCACHE_DEFAULT_LINE_SIZE;
00085 
00086 /* Each cache block holds LINE_SIZE bytes of data
00087    starting at a multiple-of-LINE_SIZE address.  */
00088 
00089 #define LINE_SIZE_MASK(dcache)  ((dcache->line_size - 1))
00090 #define XFORM(dcache, x)        ((x) & LINE_SIZE_MASK (dcache))
00091 #define MASK(dcache, x)         ((x) & ~LINE_SIZE_MASK (dcache))
00092 
00093 struct dcache_block
00094 {
00095   /* For least-recently-allocated and free lists.  */
00096   struct dcache_block *prev;
00097   struct dcache_block *next;
00098 
00099   CORE_ADDR addr;               /* address of data */
00100   int refs;                     /* # hits */
00101   gdb_byte data[1];             /* line_size bytes at given address */
00102 };
00103 
00104 struct dcache_struct
00105 {
00106   splay_tree tree;
00107   struct dcache_block *oldest; /* least-recently-allocated list.  */
00108 
00109   /* The free list is maintained identically to OLDEST to simplify
00110      the code: we only need one set of accessors.  */
00111   struct dcache_block *freelist;
00112 
00113   /* The number of in-use lines in the cache.  */
00114   int size;
00115   CORE_ADDR line_size;  /* current line_size.  */
00116 
00117   /* The ptid of last inferior to use cache or null_ptid.  */
00118   ptid_t ptid;
00119 };
00120 
00121 typedef void (block_func) (struct dcache_block *block, void *param);
00122 
00123 static struct dcache_block *dcache_hit (DCACHE *dcache, CORE_ADDR addr);
00124 
00125 static int dcache_read_line (DCACHE *dcache, struct dcache_block *db);
00126 
00127 static struct dcache_block *dcache_alloc (DCACHE *dcache, CORE_ADDR addr);
00128 
00129 static void dcache_info (char *exp, int tty);
00130 
00131 void _initialize_dcache (void);
00132 
00133 static int dcache_enabled_p = 0; /* OBSOLETE */
00134 
00135 static void
00136 show_dcache_enabled_p (struct ui_file *file, int from_tty,
00137                        struct cmd_list_element *c, const char *value)
00138 {
00139   fprintf_filtered (file, _("Deprecated remotecache flag is %s.\n"), value);
00140 }
00141 
00142 static DCACHE *last_cache; /* Used by info dcache.  */
00143 
00144 /* Add BLOCK to circular block list BLIST, behind the block at *BLIST.
00145    *BLIST is not updated (unless it was previously NULL of course).
00146    This is for the least-recently-allocated list's sake:
00147    BLIST points to the oldest block.
00148    ??? This makes for poor cache usage of the free list,
00149    but is it measurable?  */
00150 
00151 static void
00152 append_block (struct dcache_block **blist, struct dcache_block *block)
00153 {
00154   if (*blist)
00155     {
00156       block->next = *blist;
00157       block->prev = (*blist)->prev;
00158       block->prev->next = block;
00159       (*blist)->prev = block;
00160       /* We don't update *BLIST here to maintain the invariant that for the
00161          least-recently-allocated list *BLIST points to the oldest block.  */
00162     }
00163   else
00164     {
00165       block->next = block;
00166       block->prev = block;
00167       *blist = block;
00168     }
00169 }
00170 
00171 /* Remove BLOCK from circular block list BLIST.  */
00172 
00173 static void
00174 remove_block (struct dcache_block **blist, struct dcache_block *block)
00175 {
00176   if (block->next == block)
00177     {
00178       *blist = NULL;
00179     }
00180   else
00181     {
00182       block->next->prev = block->prev;
00183       block->prev->next = block->next;
00184       /* If we removed the block *BLIST points to, shift it to the next block
00185          to maintain the invariant that for the least-recently-allocated list
00186          *BLIST points to the oldest block.  */
00187       if (*blist == block)
00188         *blist = block->next;
00189     }
00190 }
00191 
00192 /* Iterate over all elements in BLIST, calling FUNC.
00193    PARAM is passed to FUNC.
00194    FUNC may remove the block it's passed, but only that block.  */
00195 
00196 static void
00197 for_each_block (struct dcache_block **blist, block_func *func, void *param)
00198 {
00199   struct dcache_block *db;
00200 
00201   if (*blist == NULL)
00202     return;
00203 
00204   db = *blist;
00205   do
00206     {
00207       struct dcache_block *next = db->next;
00208 
00209       func (db, param);
00210       db = next;
00211     }
00212   while (*blist && db != *blist);
00213 }
00214 
00215 /* BLOCK_FUNC routine for dcache_free.  */
00216 
00217 static void
00218 free_block (struct dcache_block *block, void *param)
00219 {
00220   xfree (block);
00221 }
00222 
00223 /* Free a data cache.  */
00224 
00225 void
00226 dcache_free (DCACHE *dcache)
00227 {
00228   if (last_cache == dcache)
00229     last_cache = NULL;
00230 
00231   splay_tree_delete (dcache->tree);
00232   for_each_block (&dcache->oldest, free_block, NULL);
00233   for_each_block (&dcache->freelist, free_block, NULL);
00234   xfree (dcache);
00235 }
00236 
00237 
00238 /* BLOCK_FUNC function for dcache_invalidate.
00239    This doesn't remove the block from the oldest list on purpose.
00240    dcache_invalidate will do it later.  */
00241 
00242 static void
00243 invalidate_block (struct dcache_block *block, void *param)
00244 {
00245   DCACHE *dcache = (DCACHE *) param;
00246 
00247   splay_tree_remove (dcache->tree, (splay_tree_key) block->addr);
00248   append_block (&dcache->freelist, block);
00249 }
00250 
00251 /* Free all the data cache blocks, thus discarding all cached data.  */
00252 
00253 void
00254 dcache_invalidate (DCACHE *dcache)
00255 {
00256   for_each_block (&dcache->oldest, invalidate_block, dcache);
00257 
00258   dcache->oldest = NULL;
00259   dcache->size = 0;
00260   dcache->ptid = null_ptid;
00261 
00262   if (dcache->line_size != dcache_line_size)
00263     {
00264       /* We've been asked to use a different line size.
00265          All of our freelist blocks are now the wrong size, so free them.  */
00266 
00267       for_each_block (&dcache->freelist, free_block, dcache);
00268       dcache->freelist = NULL;
00269       dcache->line_size = dcache_line_size;
00270     }
00271 }
00272 
00273 /* Invalidate the line associated with ADDR.  */
00274 
00275 static void
00276 dcache_invalidate_line (DCACHE *dcache, CORE_ADDR addr)
00277 {
00278   struct dcache_block *db = dcache_hit (dcache, addr);
00279 
00280   if (db)
00281     {
00282       splay_tree_remove (dcache->tree, (splay_tree_key) db->addr);
00283       remove_block (&dcache->oldest, db);
00284       append_block (&dcache->freelist, db);
00285       --dcache->size;
00286     }
00287 }
00288 
00289 /* If addr is present in the dcache, return the address of the block
00290    containing it.  Otherwise return NULL.  */
00291 
00292 static struct dcache_block *
00293 dcache_hit (DCACHE *dcache, CORE_ADDR addr)
00294 {
00295   struct dcache_block *db;
00296 
00297   splay_tree_node node = splay_tree_lookup (dcache->tree,
00298                                             (splay_tree_key) MASK (dcache, addr));
00299 
00300   if (!node)
00301     return NULL;
00302 
00303   db = (struct dcache_block *) node->value;
00304   db->refs++;
00305   return db;
00306 }
00307 
00308 /* Fill a cache line from target memory.
00309    The result is 1 for success, 0 if the (entire) cache line
00310    wasn't readable.  */
00311 
00312 static int
00313 dcache_read_line (DCACHE *dcache, struct dcache_block *db)
00314 {
00315   CORE_ADDR memaddr;
00316   gdb_byte *myaddr;
00317   int len;
00318   int res;
00319   int reg_len;
00320   struct mem_region *region;
00321 
00322   len = dcache->line_size;
00323   memaddr = db->addr;
00324   myaddr  = db->data;
00325 
00326   while (len > 0)
00327     {
00328       /* Don't overrun if this block is right at the end of the region.  */
00329       region = lookup_mem_region (memaddr);
00330       if (region->hi == 0 || memaddr + len < region->hi)
00331         reg_len = len;
00332       else
00333         reg_len = region->hi - memaddr;
00334 
00335       /* Skip non-readable regions.  The cache attribute can be ignored,
00336          since we may be loading this for a stack access.  */
00337       if (region->attrib.mode == MEM_WO)
00338         {
00339           memaddr += reg_len;
00340           myaddr  += reg_len;
00341           len     -= reg_len;
00342           continue;
00343         }
00344       
00345       res = target_read (&current_target, TARGET_OBJECT_RAW_MEMORY,
00346                          NULL, myaddr, memaddr, reg_len);
00347       if (res < reg_len)
00348         return 0;
00349 
00350       memaddr += res;
00351       myaddr += res;
00352       len -= res;
00353     }
00354 
00355   return 1;
00356 }
00357 
00358 /* Get a free cache block, put or keep it on the valid list,
00359    and return its address.  */
00360 
00361 static struct dcache_block *
00362 dcache_alloc (DCACHE *dcache, CORE_ADDR addr)
00363 {
00364   struct dcache_block *db;
00365 
00366   if (dcache->size >= dcache_size)
00367     {
00368       /* Evict the least recently allocated line.  */
00369       db = dcache->oldest;
00370       remove_block (&dcache->oldest, db);
00371 
00372       splay_tree_remove (dcache->tree, (splay_tree_key) db->addr);
00373     }
00374   else
00375     {
00376       db = dcache->freelist;
00377       if (db)
00378         remove_block (&dcache->freelist, db);
00379       else
00380         db = xmalloc (offsetof (struct dcache_block, data) +
00381                       dcache->line_size);
00382 
00383       dcache->size++;
00384     }
00385 
00386   db->addr = MASK (dcache, addr);
00387   db->refs = 0;
00388 
00389   /* Put DB at the end of the list, it's the newest.  */
00390   append_block (&dcache->oldest, db);
00391 
00392   splay_tree_insert (dcache->tree, (splay_tree_key) db->addr,
00393                      (splay_tree_value) db);
00394 
00395   return db;
00396 }
00397 
00398 /* Using the data cache DCACHE, store in *PTR the contents of the byte at
00399    address ADDR in the remote machine.  
00400 
00401    Returns 1 for success, 0 for error.  */
00402 
00403 static int
00404 dcache_peek_byte (DCACHE *dcache, CORE_ADDR addr, gdb_byte *ptr)
00405 {
00406   struct dcache_block *db = dcache_hit (dcache, addr);
00407 
00408   if (!db)
00409     {
00410       db = dcache_alloc (dcache, addr);
00411 
00412       if (!dcache_read_line (dcache, db))
00413          return 0;
00414     }
00415 
00416   *ptr = db->data[XFORM (dcache, addr)];
00417   return 1;
00418 }
00419 
00420 /* Write the byte at PTR into ADDR in the data cache.
00421 
00422    The caller is responsible for also promptly writing the data
00423    through to target memory.
00424 
00425    If addr is not in cache, this function does nothing; writing to
00426    an area of memory which wasn't present in the cache doesn't cause
00427    it to be loaded in.
00428 
00429    Always return 1 (meaning success) to simplify dcache_xfer_memory.  */
00430 
00431 static int
00432 dcache_poke_byte (DCACHE *dcache, CORE_ADDR addr, gdb_byte *ptr)
00433 {
00434   struct dcache_block *db = dcache_hit (dcache, addr);
00435 
00436   if (db)
00437     db->data[XFORM (dcache, addr)] = *ptr;
00438 
00439   return 1;
00440 }
00441 
00442 static int
00443 dcache_splay_tree_compare (splay_tree_key a, splay_tree_key b)
00444 {
00445   if (a > b)
00446     return 1;
00447   else if (a == b)
00448     return 0;
00449   else
00450     return -1;
00451 }
00452 
00453 /* Allocate and initialize a data cache.  */
00454 
00455 DCACHE *
00456 dcache_init (void)
00457 {
00458   DCACHE *dcache;
00459 
00460   dcache = (DCACHE *) xmalloc (sizeof (*dcache));
00461 
00462   dcache->tree = splay_tree_new (dcache_splay_tree_compare,
00463                                  NULL,
00464                                  NULL);
00465 
00466   dcache->oldest = NULL;
00467   dcache->freelist = NULL;
00468   dcache->size = 0;
00469   dcache->line_size = dcache_line_size;
00470   dcache->ptid = null_ptid;
00471   last_cache = dcache;
00472 
00473   return dcache;
00474 }
00475 
00476 
00477 /* Read or write LEN bytes from inferior memory at MEMADDR, transferring
00478    to or from debugger address MYADDR.  Write to inferior if SHOULD_WRITE is
00479    nonzero. 
00480 
00481    Return the number of bytes actually transfered, or -1 if the
00482    transfer is not supported or otherwise fails.  Return of a non-negative
00483    value less than LEN indicates that no further transfer is possible.
00484    NOTE: This is different than the to_xfer_partial interface, in which
00485    positive values less than LEN mean further transfers may be possible.  */
00486 
00487 int
00488 dcache_xfer_memory (struct target_ops *ops, DCACHE *dcache,
00489                     CORE_ADDR memaddr, gdb_byte *myaddr,
00490                     int len, int should_write)
00491 {
00492   int i;
00493   int res;
00494   int (*xfunc) (DCACHE *dcache, CORE_ADDR addr, gdb_byte *ptr);
00495 
00496   xfunc = should_write ? dcache_poke_byte : dcache_peek_byte;
00497 
00498   /* If this is a different inferior from what we've recorded,
00499      flush the cache.  */
00500 
00501   if (! ptid_equal (inferior_ptid, dcache->ptid))
00502     {
00503       dcache_invalidate (dcache);
00504       dcache->ptid = inferior_ptid;
00505     }
00506 
00507   /* Do write-through first, so that if it fails, we don't write to
00508      the cache at all.  */
00509 
00510   if (should_write)
00511     {
00512       res = target_write (ops, TARGET_OBJECT_RAW_MEMORY,
00513                           NULL, myaddr, memaddr, len);
00514       if (res <= 0)
00515         return res;
00516       /* Update LEN to what was actually written.  */
00517       len = res;
00518     }
00519       
00520   for (i = 0; i < len; i++)
00521     {
00522       if (!xfunc (dcache, memaddr + i, myaddr + i))
00523         {
00524           /* That failed.  Discard its cache line so we don't have a
00525              partially read line.  */
00526           dcache_invalidate_line (dcache, memaddr + i);
00527           /* If we're writing, we still wrote LEN bytes.  */
00528           if (should_write)
00529             return len;
00530           else
00531             return i;
00532         }
00533     }
00534     
00535   return len;
00536 }
00537 
00538 /* FIXME: There would be some benefit to making the cache write-back and
00539    moving the writeback operation to a higher layer, as it could occur
00540    after a sequence of smaller writes have been completed (as when a stack
00541    frame is constructed for an inferior function call).  Note that only
00542    moving it up one level to target_xfer_memory[_partial]() is not
00543    sufficient since we want to coalesce memory transfers that are
00544    "logically" connected but not actually a single call to one of the
00545    memory transfer functions.  */
00546 
00547 /* Just update any cache lines which are already present.  This is called
00548    by memory_xfer_partial in cases where the access would otherwise not go
00549    through the cache.  */
00550 
00551 void
00552 dcache_update (DCACHE *dcache, CORE_ADDR memaddr, gdb_byte *myaddr, int len)
00553 {
00554   int i;
00555 
00556   for (i = 0; i < len; i++)
00557     dcache_poke_byte (dcache, memaddr + i, myaddr + i);
00558 }
00559 
00560 static void
00561 dcache_print_line (int index)
00562 {
00563   splay_tree_node n;
00564   struct dcache_block *db;
00565   int i, j;
00566 
00567   if (!last_cache)
00568     {
00569       printf_filtered (_("No data cache available.\n"));
00570       return;
00571     }
00572 
00573   n = splay_tree_min (last_cache->tree);
00574 
00575   for (i = index; i > 0; --i)
00576     {
00577       if (!n)
00578         break;
00579       n = splay_tree_successor (last_cache->tree, n->key);
00580     }
00581 
00582   if (!n)
00583     {
00584       printf_filtered (_("No such cache line exists.\n"));
00585       return;
00586     }
00587     
00588   db = (struct dcache_block *) n->value;
00589 
00590   printf_filtered (_("Line %d: address %s [%d hits]\n"),
00591                    index, paddress (target_gdbarch (), db->addr), db->refs);
00592 
00593   for (j = 0; j < last_cache->line_size; j++)
00594     {
00595       printf_filtered ("%02x ", db->data[j]);
00596 
00597       /* Print a newline every 16 bytes (48 characters).  */
00598       if ((j % 16 == 15) && (j != last_cache->line_size - 1))
00599         printf_filtered ("\n");
00600     }
00601   printf_filtered ("\n");
00602 }
00603 
00604 static void
00605 dcache_info (char *exp, int tty)
00606 {
00607   splay_tree_node n;
00608   int i, refcount;
00609 
00610   if (exp)
00611     {
00612       char *linestart;
00613 
00614       i = strtol (exp, &linestart, 10);
00615       if (linestart == exp || i < 0)
00616         {
00617           printf_filtered (_("Usage: info dcache [linenumber]\n"));
00618           return;
00619         }
00620 
00621       dcache_print_line (i);
00622       return;
00623     }
00624 
00625   printf_filtered (_("Dcache %u lines of %u bytes each.\n"),
00626                    dcache_size,
00627                    last_cache ? (unsigned) last_cache->line_size
00628                    : dcache_line_size);
00629 
00630   if (!last_cache || ptid_equal (last_cache->ptid, null_ptid))
00631     {
00632       printf_filtered (_("No data cache available.\n"));
00633       return;
00634     }
00635 
00636   printf_filtered (_("Contains data for %s\n"),
00637                    target_pid_to_str (last_cache->ptid));
00638 
00639   refcount = 0;
00640 
00641   n = splay_tree_min (last_cache->tree);
00642   i = 0;
00643 
00644   while (n)
00645     {
00646       struct dcache_block *db = (struct dcache_block *) n->value;
00647 
00648       printf_filtered (_("Line %d: address %s [%d hits]\n"),
00649                        i, paddress (target_gdbarch (), db->addr), db->refs);
00650       i++;
00651       refcount += db->refs;
00652 
00653       n = splay_tree_successor (last_cache->tree, n->key);
00654     }
00655 
00656   printf_filtered (_("Cache state: %d active lines, %d hits\n"), i, refcount);
00657 }
00658 
00659 static void
00660 set_dcache_size (char *args, int from_tty,
00661                  struct cmd_list_element *c)
00662 {
00663   if (dcache_size == 0)
00664     {
00665       dcache_size = DCACHE_DEFAULT_SIZE;
00666       error (_("Dcache size must be greater than 0."));
00667     }
00668   if (last_cache)
00669     dcache_invalidate (last_cache);
00670 }
00671 
00672 static void
00673 set_dcache_line_size (char *args, int from_tty,
00674                       struct cmd_list_element *c)
00675 {
00676   if (dcache_line_size < 2
00677       || (dcache_line_size & (dcache_line_size - 1)) != 0)
00678     {
00679       unsigned d = dcache_line_size;
00680       dcache_line_size = DCACHE_DEFAULT_LINE_SIZE;
00681       error (_("Invalid dcache line size: %u (must be power of 2)."), d);
00682     }
00683   if (last_cache)
00684     dcache_invalidate (last_cache);
00685 }
00686 
00687 static void
00688 set_dcache_command (char *arg, int from_tty)
00689 {
00690   printf_unfiltered (
00691      "\"set dcache\" must be followed by the name of a subcommand.\n");
00692   help_list (dcache_set_list, "set dcache ", -1, gdb_stdout);
00693 }
00694 
00695 static void
00696 show_dcache_command (char *args, int from_tty)
00697 {
00698   cmd_show_list (dcache_show_list, from_tty, "");
00699 }
00700 
00701 void
00702 _initialize_dcache (void)
00703 {
00704   add_setshow_boolean_cmd ("remotecache", class_support,
00705                            &dcache_enabled_p, _("\
00706 Set cache use for remote targets."), _("\
00707 Show cache use for remote targets."), _("\
00708 This used to enable the data cache for remote targets.  The cache\n\
00709 functionality is now controlled by the memory region system and the\n\
00710 \"stack-cache\" flag; \"remotecache\" now does nothing and\n\
00711 exists only for compatibility reasons."),
00712                            NULL,
00713                            show_dcache_enabled_p,
00714                            &setlist, &showlist);
00715 
00716   add_info ("dcache", dcache_info,
00717             _("\
00718 Print information on the dcache performance.\n\
00719 With no arguments, this command prints the cache configuration and a\n\
00720 summary of each line in the cache.  Use \"info dcache <lineno> to dump\"\n\
00721 the contents of a given line."));
00722 
00723   add_prefix_cmd ("dcache", class_obscure, set_dcache_command, _("\
00724 Use this command to set number of lines in dcache and line-size."),
00725                   &dcache_set_list, "set dcache ", /*allow_unknown*/0, &setlist);
00726   add_prefix_cmd ("dcache", class_obscure, show_dcache_command, _("\
00727 Show dcachesettings."),
00728                   &dcache_show_list, "show dcache ", /*allow_unknown*/0, &showlist);
00729 
00730   add_setshow_zuinteger_cmd ("line-size", class_obscure,
00731                              &dcache_line_size, _("\
00732 Set dcache line size in bytes (must be power of 2)."), _("\
00733 Show dcache line size."),
00734                              NULL,
00735                              set_dcache_line_size,
00736                              NULL,
00737                              &dcache_set_list, &dcache_show_list);
00738   add_setshow_zuinteger_cmd ("size", class_obscure,
00739                              &dcache_size, _("\
00740 Set number of dcache lines."), _("\
00741 Show number of dcache lines."),
00742                              NULL,
00743                              set_dcache_size,
00744                              NULL,
00745                              &dcache_set_list, &dcache_show_list);
00746 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines