GDB (API)
|
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 (¤t_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 }