xref: /dflybsd-src/contrib/gdb-7/gdb/dcache.c (revision cf7f2e2d389e8012d562650bd94d7e433f449d6e)
15796c8dcSSimon Schubert /* Caching code for GDB, the GNU debugger.
25796c8dcSSimon Schubert 
35796c8dcSSimon Schubert    Copyright (C) 1992, 1993, 1995, 1996, 1998, 1999, 2000, 2001, 2003, 2007,
4*cf7f2e2dSJohn Marino    2008, 2009, 2010 Free Software Foundation, Inc.
55796c8dcSSimon Schubert 
65796c8dcSSimon Schubert    This file is part of GDB.
75796c8dcSSimon Schubert 
85796c8dcSSimon Schubert    This program is free software; you can redistribute it and/or modify
95796c8dcSSimon Schubert    it under the terms of the GNU General Public License as published by
105796c8dcSSimon Schubert    the Free Software Foundation; either version 3 of the License, or
115796c8dcSSimon Schubert    (at your option) any later version.
125796c8dcSSimon Schubert 
135796c8dcSSimon Schubert    This program is distributed in the hope that it will be useful,
145796c8dcSSimon Schubert    but WITHOUT ANY WARRANTY; without even the implied warranty of
155796c8dcSSimon Schubert    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
165796c8dcSSimon Schubert    GNU General Public License for more details.
175796c8dcSSimon Schubert 
185796c8dcSSimon Schubert    You should have received a copy of the GNU General Public License
195796c8dcSSimon Schubert    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
205796c8dcSSimon Schubert 
215796c8dcSSimon Schubert #include "defs.h"
225796c8dcSSimon Schubert #include "dcache.h"
235796c8dcSSimon Schubert #include "gdbcmd.h"
245796c8dcSSimon Schubert #include "gdb_string.h"
255796c8dcSSimon Schubert #include "gdbcore.h"
265796c8dcSSimon Schubert #include "target.h"
275796c8dcSSimon Schubert #include "inferior.h"
285796c8dcSSimon Schubert #include "splay-tree.h"
295796c8dcSSimon Schubert 
305796c8dcSSimon Schubert /* The data cache could lead to incorrect results because it doesn't
315796c8dcSSimon Schubert    know about volatile variables, thus making it impossible to debug
325796c8dcSSimon Schubert    functions which use memory mapped I/O devices.  Set the nocache
335796c8dcSSimon Schubert    memory region attribute in those cases.
345796c8dcSSimon Schubert 
355796c8dcSSimon Schubert    In general the dcache speeds up performance.  Some speed improvement
365796c8dcSSimon Schubert    comes from the actual caching mechanism, but the major gain is in
375796c8dcSSimon Schubert    the reduction of the remote protocol overhead; instead of reading
385796c8dcSSimon Schubert    or writing a large area of memory in 4 byte requests, the cache
395796c8dcSSimon Schubert    bundles up the requests into LINE_SIZE chunks, reducing overhead
405796c8dcSSimon Schubert    significantly.  This is most useful when accessing a large amount
415796c8dcSSimon Schubert    of data, such as when performing a backtrace.
425796c8dcSSimon Schubert 
435796c8dcSSimon Schubert    The cache is a splay tree along with a linked list for replacement.
44*cf7f2e2dSJohn Marino    Each block caches a LINE_SIZE area of memory.  Within each line we
45*cf7f2e2dSJohn Marino    remember the address of the line (which must be a multiple of
46*cf7f2e2dSJohn Marino    LINE_SIZE) and the actual data block.
475796c8dcSSimon Schubert 
485796c8dcSSimon Schubert    Lines are only allocated as needed, so DCACHE_SIZE really specifies the
495796c8dcSSimon Schubert    *maximum* number of lines in the cache.
505796c8dcSSimon Schubert 
515796c8dcSSimon Schubert    At present, the cache is write-through rather than writeback: as soon
525796c8dcSSimon Schubert    as data is written to the cache, it is also immediately written to
535796c8dcSSimon Schubert    the target.  Therefore, cache lines are never "dirty".  Whether a given
545796c8dcSSimon Schubert    line is valid or not depends on where it is stored in the dcache_struct;
555796c8dcSSimon Schubert    there is no per-block valid flag.  */
565796c8dcSSimon Schubert 
575796c8dcSSimon Schubert /* NOTE: Interaction of dcache and memory region attributes
585796c8dcSSimon Schubert 
595796c8dcSSimon Schubert    As there is no requirement that memory region attributes be aligned
605796c8dcSSimon Schubert    to or be a multiple of the dcache page size, dcache_read_line() and
615796c8dcSSimon Schubert    dcache_write_line() must break up the page by memory region.  If a
625796c8dcSSimon Schubert    chunk does not have the cache attribute set, an invalid memory type
635796c8dcSSimon Schubert    is set, etc., then the chunk is skipped.  Those chunks are handled
645796c8dcSSimon Schubert    in target_xfer_memory() (or target_xfer_memory_partial()).
655796c8dcSSimon Schubert 
665796c8dcSSimon Schubert    This doesn't occur very often.  The most common occurance is when
675796c8dcSSimon Schubert    the last bit of the .text segment and the first bit of the .data
685796c8dcSSimon Schubert    segment fall within the same dcache page with a ro/cacheable memory
695796c8dcSSimon Schubert    region defined for the .text segment and a rw/non-cacheable memory
705796c8dcSSimon Schubert    region defined for the .data segment.  */
715796c8dcSSimon Schubert 
725796c8dcSSimon Schubert /* The maximum number of lines stored.  The total size of the cache is
735796c8dcSSimon Schubert    equal to DCACHE_SIZE times LINE_SIZE.  */
745796c8dcSSimon Schubert #define DCACHE_SIZE 4096
755796c8dcSSimon Schubert 
765796c8dcSSimon Schubert /* The size of a cache line.  Smaller values reduce the time taken to
775796c8dcSSimon Schubert    read a single byte and make the cache more granular, but increase
785796c8dcSSimon Schubert    overhead and reduce the effectiveness of the cache as a prefetcher.  */
795796c8dcSSimon Schubert #define LINE_SIZE_POWER 6
805796c8dcSSimon Schubert #define LINE_SIZE (1 << LINE_SIZE_POWER)
815796c8dcSSimon Schubert 
825796c8dcSSimon Schubert /* Each cache block holds LINE_SIZE bytes of data
835796c8dcSSimon Schubert    starting at a multiple-of-LINE_SIZE address.  */
845796c8dcSSimon Schubert 
855796c8dcSSimon Schubert #define LINE_SIZE_MASK  ((LINE_SIZE - 1))
865796c8dcSSimon Schubert #define XFORM(x) 	((x) & LINE_SIZE_MASK)
875796c8dcSSimon Schubert #define MASK(x)         ((x) & ~LINE_SIZE_MASK)
885796c8dcSSimon Schubert 
895796c8dcSSimon Schubert struct dcache_block
905796c8dcSSimon Schubert {
91*cf7f2e2dSJohn Marino   /* for least-recently-allocated and free lists */
92*cf7f2e2dSJohn Marino   struct dcache_block *prev;
93*cf7f2e2dSJohn Marino   struct dcache_block *next;
94*cf7f2e2dSJohn Marino 
955796c8dcSSimon Schubert   CORE_ADDR addr;		/* address of data */
965796c8dcSSimon Schubert   gdb_byte data[LINE_SIZE];	/* bytes at given address */
975796c8dcSSimon Schubert   int refs;			/* # hits */
985796c8dcSSimon Schubert };
995796c8dcSSimon Schubert 
1005796c8dcSSimon Schubert struct dcache_struct
1015796c8dcSSimon Schubert {
1025796c8dcSSimon Schubert   splay_tree tree;
103*cf7f2e2dSJohn Marino   struct dcache_block *oldest; /* least-recently-allocated list */
1045796c8dcSSimon Schubert 
105*cf7f2e2dSJohn Marino   /* The free list is maintained identically to OLDEST to simplify
106*cf7f2e2dSJohn Marino      the code: we only need one set of accessors.  */
1075796c8dcSSimon Schubert   struct dcache_block *freelist;
1085796c8dcSSimon Schubert 
1095796c8dcSSimon Schubert   /* The number of in-use lines in the cache.  */
1105796c8dcSSimon Schubert   int size;
1115796c8dcSSimon Schubert 
1125796c8dcSSimon Schubert   /* The ptid of last inferior to use cache or null_ptid.  */
1135796c8dcSSimon Schubert   ptid_t ptid;
1145796c8dcSSimon Schubert };
1155796c8dcSSimon Schubert 
116*cf7f2e2dSJohn Marino typedef void (block_func) (struct dcache_block *block, void *param);
1175796c8dcSSimon Schubert 
118*cf7f2e2dSJohn Marino static struct dcache_block *dcache_hit (DCACHE *dcache, CORE_ADDR addr);
1195796c8dcSSimon Schubert 
1205796c8dcSSimon Schubert static int dcache_read_line (DCACHE *dcache, struct dcache_block *db);
1215796c8dcSSimon Schubert 
1225796c8dcSSimon Schubert static struct dcache_block *dcache_alloc (DCACHE *dcache, CORE_ADDR addr);
1235796c8dcSSimon Schubert 
1245796c8dcSSimon Schubert static void dcache_info (char *exp, int tty);
1255796c8dcSSimon Schubert 
1265796c8dcSSimon Schubert void _initialize_dcache (void);
1275796c8dcSSimon Schubert 
1285796c8dcSSimon Schubert static int dcache_enabled_p = 0; /* OBSOLETE */
1295796c8dcSSimon Schubert 
1305796c8dcSSimon Schubert static void
1315796c8dcSSimon Schubert show_dcache_enabled_p (struct ui_file *file, int from_tty,
1325796c8dcSSimon Schubert 		       struct cmd_list_element *c, const char *value)
1335796c8dcSSimon Schubert {
1345796c8dcSSimon Schubert   fprintf_filtered (file, _("Deprecated remotecache flag is %s.\n"), value);
1355796c8dcSSimon Schubert }
1365796c8dcSSimon Schubert 
1375796c8dcSSimon Schubert static DCACHE *last_cache; /* Used by info dcache */
1385796c8dcSSimon Schubert 
139*cf7f2e2dSJohn Marino /* Add BLOCK to circular block list BLIST, behind the block at *BLIST.
140*cf7f2e2dSJohn Marino    *BLIST is not updated (unless it was previously NULL of course).
141*cf7f2e2dSJohn Marino    This is for the least-recently-allocated list's sake:
142*cf7f2e2dSJohn Marino    BLIST points to the oldest block.
143*cf7f2e2dSJohn Marino    ??? This makes for poor cache usage of the free list,
144*cf7f2e2dSJohn Marino    but is it measurable?  */
145*cf7f2e2dSJohn Marino 
146*cf7f2e2dSJohn Marino static void
147*cf7f2e2dSJohn Marino append_block (struct dcache_block **blist, struct dcache_block *block)
148*cf7f2e2dSJohn Marino {
149*cf7f2e2dSJohn Marino   if (*blist)
150*cf7f2e2dSJohn Marino     {
151*cf7f2e2dSJohn Marino       block->next = *blist;
152*cf7f2e2dSJohn Marino       block->prev = (*blist)->prev;
153*cf7f2e2dSJohn Marino       block->prev->next = block;
154*cf7f2e2dSJohn Marino       (*blist)->prev = block;
155*cf7f2e2dSJohn Marino       /* We don't update *BLIST here to maintain the invariant that for the
156*cf7f2e2dSJohn Marino 	 least-recently-allocated list *BLIST points to the oldest block.  */
157*cf7f2e2dSJohn Marino     }
158*cf7f2e2dSJohn Marino   else
159*cf7f2e2dSJohn Marino     {
160*cf7f2e2dSJohn Marino       block->next = block;
161*cf7f2e2dSJohn Marino       block->prev = block;
162*cf7f2e2dSJohn Marino       *blist = block;
163*cf7f2e2dSJohn Marino     }
164*cf7f2e2dSJohn Marino }
165*cf7f2e2dSJohn Marino 
166*cf7f2e2dSJohn Marino /* Remove BLOCK from circular block list BLIST.  */
167*cf7f2e2dSJohn Marino 
168*cf7f2e2dSJohn Marino static void
169*cf7f2e2dSJohn Marino remove_block (struct dcache_block **blist, struct dcache_block *block)
170*cf7f2e2dSJohn Marino {
171*cf7f2e2dSJohn Marino   if (block->next == block)
172*cf7f2e2dSJohn Marino     {
173*cf7f2e2dSJohn Marino       *blist = NULL;
174*cf7f2e2dSJohn Marino     }
175*cf7f2e2dSJohn Marino   else
176*cf7f2e2dSJohn Marino     {
177*cf7f2e2dSJohn Marino       block->next->prev = block->prev;
178*cf7f2e2dSJohn Marino       block->prev->next = block->next;
179*cf7f2e2dSJohn Marino       /* If we removed the block *BLIST points to, shift it to the next block
180*cf7f2e2dSJohn Marino 	 to maintain the invariant that for the least-recently-allocated list
181*cf7f2e2dSJohn Marino 	 *BLIST points to the oldest block.  */
182*cf7f2e2dSJohn Marino       if (*blist == block)
183*cf7f2e2dSJohn Marino 	*blist = block->next;
184*cf7f2e2dSJohn Marino     }
185*cf7f2e2dSJohn Marino }
186*cf7f2e2dSJohn Marino 
187*cf7f2e2dSJohn Marino /* Iterate over all elements in BLIST, calling FUNC.
188*cf7f2e2dSJohn Marino    PARAM is passed to FUNC.
189*cf7f2e2dSJohn Marino    FUNC may remove the block it's passed, but only that block.  */
190*cf7f2e2dSJohn Marino 
191*cf7f2e2dSJohn Marino static void
192*cf7f2e2dSJohn Marino for_each_block (struct dcache_block **blist, block_func *func, void *param)
193*cf7f2e2dSJohn Marino {
194*cf7f2e2dSJohn Marino   struct dcache_block *db;
195*cf7f2e2dSJohn Marino 
196*cf7f2e2dSJohn Marino   if (*blist == NULL)
197*cf7f2e2dSJohn Marino     return;
198*cf7f2e2dSJohn Marino 
199*cf7f2e2dSJohn Marino   db = *blist;
200*cf7f2e2dSJohn Marino   do
201*cf7f2e2dSJohn Marino     {
202*cf7f2e2dSJohn Marino       struct dcache_block *next = db->next;
203*cf7f2e2dSJohn Marino 
204*cf7f2e2dSJohn Marino       func (db, param);
205*cf7f2e2dSJohn Marino       db = next;
206*cf7f2e2dSJohn Marino     }
207*cf7f2e2dSJohn Marino   while (*blist && db != *blist);
208*cf7f2e2dSJohn Marino }
209*cf7f2e2dSJohn Marino 
210*cf7f2e2dSJohn Marino /* BLOCK_FUNC function for dcache_invalidate.
211*cf7f2e2dSJohn Marino    This doesn't remove the block from the oldest list on purpose.
212*cf7f2e2dSJohn Marino    dcache_invalidate will do it later.  */
213*cf7f2e2dSJohn Marino 
214*cf7f2e2dSJohn Marino static void
215*cf7f2e2dSJohn Marino invalidate_block (struct dcache_block *block, void *param)
216*cf7f2e2dSJohn Marino {
217*cf7f2e2dSJohn Marino   DCACHE *dcache = (DCACHE *) param;
218*cf7f2e2dSJohn Marino 
219*cf7f2e2dSJohn Marino   splay_tree_remove (dcache->tree, (splay_tree_key) block->addr);
220*cf7f2e2dSJohn Marino   append_block (&dcache->freelist, block);
221*cf7f2e2dSJohn Marino }
222*cf7f2e2dSJohn Marino 
2235796c8dcSSimon Schubert /* Free all the data cache blocks, thus discarding all cached data.  */
2245796c8dcSSimon Schubert 
2255796c8dcSSimon Schubert void
2265796c8dcSSimon Schubert dcache_invalidate (DCACHE *dcache)
2275796c8dcSSimon Schubert {
228*cf7f2e2dSJohn Marino   for_each_block (&dcache->oldest, invalidate_block, dcache);
2295796c8dcSSimon Schubert 
2305796c8dcSSimon Schubert   dcache->oldest = NULL;
2315796c8dcSSimon Schubert   dcache->size = 0;
2325796c8dcSSimon Schubert   dcache->ptid = null_ptid;
2335796c8dcSSimon Schubert }
2345796c8dcSSimon Schubert 
2355796c8dcSSimon Schubert /* Invalidate the line associated with ADDR.  */
2365796c8dcSSimon Schubert 
2375796c8dcSSimon Schubert static void
2385796c8dcSSimon Schubert dcache_invalidate_line (DCACHE *dcache, CORE_ADDR addr)
2395796c8dcSSimon Schubert {
2405796c8dcSSimon Schubert   struct dcache_block *db = dcache_hit (dcache, addr);
2415796c8dcSSimon Schubert 
2425796c8dcSSimon Schubert   if (db)
2435796c8dcSSimon Schubert     {
2445796c8dcSSimon Schubert       splay_tree_remove (dcache->tree, (splay_tree_key) db->addr);
245*cf7f2e2dSJohn Marino       remove_block (&dcache->oldest, db);
246*cf7f2e2dSJohn Marino       append_block (&dcache->freelist, db);
2475796c8dcSSimon Schubert       --dcache->size;
2485796c8dcSSimon Schubert     }
2495796c8dcSSimon Schubert }
2505796c8dcSSimon Schubert 
2515796c8dcSSimon Schubert /* If addr is present in the dcache, return the address of the block
252*cf7f2e2dSJohn Marino    containing it.  Otherwise return NULL.  */
2535796c8dcSSimon Schubert 
2545796c8dcSSimon Schubert static struct dcache_block *
2555796c8dcSSimon Schubert dcache_hit (DCACHE *dcache, CORE_ADDR addr)
2565796c8dcSSimon Schubert {
2575796c8dcSSimon Schubert   struct dcache_block *db;
2585796c8dcSSimon Schubert 
2595796c8dcSSimon Schubert   splay_tree_node node = splay_tree_lookup (dcache->tree,
2605796c8dcSSimon Schubert 					    (splay_tree_key) MASK (addr));
2615796c8dcSSimon Schubert 
2625796c8dcSSimon Schubert   if (!node)
2635796c8dcSSimon Schubert     return NULL;
2645796c8dcSSimon Schubert 
2655796c8dcSSimon Schubert   db = (struct dcache_block *) node->value;
2665796c8dcSSimon Schubert   db->refs++;
2675796c8dcSSimon Schubert   return db;
2685796c8dcSSimon Schubert }
2695796c8dcSSimon Schubert 
270*cf7f2e2dSJohn Marino /* Fill a cache line from target memory.
271*cf7f2e2dSJohn Marino    The result is 1 for success, 0 if the (entire) cache line
272*cf7f2e2dSJohn Marino    wasn't readable.  */
2735796c8dcSSimon Schubert 
2745796c8dcSSimon Schubert static int
2755796c8dcSSimon Schubert dcache_read_line (DCACHE *dcache, struct dcache_block *db)
2765796c8dcSSimon Schubert {
2775796c8dcSSimon Schubert   CORE_ADDR memaddr;
2785796c8dcSSimon Schubert   gdb_byte *myaddr;
2795796c8dcSSimon Schubert   int len;
2805796c8dcSSimon Schubert   int res;
2815796c8dcSSimon Schubert   int reg_len;
2825796c8dcSSimon Schubert   struct mem_region *region;
2835796c8dcSSimon Schubert 
2845796c8dcSSimon Schubert   len = LINE_SIZE;
2855796c8dcSSimon Schubert   memaddr = db->addr;
2865796c8dcSSimon Schubert   myaddr  = db->data;
2875796c8dcSSimon Schubert 
2885796c8dcSSimon Schubert   while (len > 0)
2895796c8dcSSimon Schubert     {
2905796c8dcSSimon Schubert       /* Don't overrun if this block is right at the end of the region.  */
2915796c8dcSSimon Schubert       region = lookup_mem_region (memaddr);
2925796c8dcSSimon Schubert       if (region->hi == 0 || memaddr + len < region->hi)
2935796c8dcSSimon Schubert 	reg_len = len;
2945796c8dcSSimon Schubert       else
2955796c8dcSSimon Schubert 	reg_len = region->hi - memaddr;
2965796c8dcSSimon Schubert 
2975796c8dcSSimon Schubert       /* Skip non-readable regions.  The cache attribute can be ignored,
2985796c8dcSSimon Schubert          since we may be loading this for a stack access.  */
2995796c8dcSSimon Schubert       if (region->attrib.mode == MEM_WO)
3005796c8dcSSimon Schubert 	{
3015796c8dcSSimon Schubert 	  memaddr += reg_len;
3025796c8dcSSimon Schubert 	  myaddr  += reg_len;
3035796c8dcSSimon Schubert 	  len     -= reg_len;
3045796c8dcSSimon Schubert 	  continue;
3055796c8dcSSimon Schubert 	}
3065796c8dcSSimon Schubert 
3075796c8dcSSimon Schubert       res = target_read (&current_target, TARGET_OBJECT_RAW_MEMORY,
3085796c8dcSSimon Schubert 			 NULL, myaddr, memaddr, reg_len);
3095796c8dcSSimon Schubert       if (res < reg_len)
3105796c8dcSSimon Schubert 	return 0;
3115796c8dcSSimon Schubert 
3125796c8dcSSimon Schubert       memaddr += res;
3135796c8dcSSimon Schubert       myaddr += res;
3145796c8dcSSimon Schubert       len -= res;
3155796c8dcSSimon Schubert     }
3165796c8dcSSimon Schubert 
3175796c8dcSSimon Schubert   return 1;
3185796c8dcSSimon Schubert }
3195796c8dcSSimon Schubert 
3205796c8dcSSimon Schubert /* Get a free cache block, put or keep it on the valid list,
3215796c8dcSSimon Schubert    and return its address.  */
3225796c8dcSSimon Schubert 
3235796c8dcSSimon Schubert static struct dcache_block *
3245796c8dcSSimon Schubert dcache_alloc (DCACHE *dcache, CORE_ADDR addr)
3255796c8dcSSimon Schubert {
3265796c8dcSSimon Schubert   struct dcache_block *db;
3275796c8dcSSimon Schubert 
3285796c8dcSSimon Schubert   if (dcache->size >= DCACHE_SIZE)
3295796c8dcSSimon Schubert     {
330*cf7f2e2dSJohn Marino       /* Evict the least recently allocated line.  */
3315796c8dcSSimon Schubert       db = dcache->oldest;
332*cf7f2e2dSJohn Marino       remove_block (&dcache->oldest, db);
3335796c8dcSSimon Schubert 
3345796c8dcSSimon Schubert       splay_tree_remove (dcache->tree, (splay_tree_key) db->addr);
3355796c8dcSSimon Schubert     }
3365796c8dcSSimon Schubert   else
3375796c8dcSSimon Schubert     {
3385796c8dcSSimon Schubert       db = dcache->freelist;
3395796c8dcSSimon Schubert       if (db)
340*cf7f2e2dSJohn Marino 	remove_block (&dcache->freelist, db);
3415796c8dcSSimon Schubert       else
3425796c8dcSSimon Schubert 	db = xmalloc (sizeof (struct dcache_block));
3435796c8dcSSimon Schubert 
3445796c8dcSSimon Schubert       dcache->size++;
3455796c8dcSSimon Schubert     }
3465796c8dcSSimon Schubert 
3475796c8dcSSimon Schubert   db->addr = MASK (addr);
3485796c8dcSSimon Schubert   db->refs = 0;
3495796c8dcSSimon Schubert 
350*cf7f2e2dSJohn Marino   /* Put DB at the end of the list, it's the newest.  */
351*cf7f2e2dSJohn Marino   append_block (&dcache->oldest, db);
3525796c8dcSSimon Schubert 
3535796c8dcSSimon Schubert   splay_tree_insert (dcache->tree, (splay_tree_key) db->addr,
3545796c8dcSSimon Schubert 		     (splay_tree_value) db);
3555796c8dcSSimon Schubert 
3565796c8dcSSimon Schubert   return db;
3575796c8dcSSimon Schubert }
3585796c8dcSSimon Schubert 
359*cf7f2e2dSJohn Marino /* Using the data cache DCACHE, store in *PTR the contents of the byte at
3605796c8dcSSimon Schubert    address ADDR in the remote machine.
3615796c8dcSSimon Schubert 
3625796c8dcSSimon Schubert    Returns 1 for success, 0 for error.  */
3635796c8dcSSimon Schubert 
3645796c8dcSSimon Schubert static int
3655796c8dcSSimon Schubert dcache_peek_byte (DCACHE *dcache, CORE_ADDR addr, gdb_byte *ptr)
3665796c8dcSSimon Schubert {
3675796c8dcSSimon Schubert   struct dcache_block *db = dcache_hit (dcache, addr);
3685796c8dcSSimon Schubert 
3695796c8dcSSimon Schubert   if (!db)
3705796c8dcSSimon Schubert     {
3715796c8dcSSimon Schubert       db = dcache_alloc (dcache, addr);
3725796c8dcSSimon Schubert 
3735796c8dcSSimon Schubert       if (!dcache_read_line (dcache, db))
3745796c8dcSSimon Schubert          return 0;
3755796c8dcSSimon Schubert     }
3765796c8dcSSimon Schubert 
3775796c8dcSSimon Schubert   *ptr = db->data[XFORM (addr)];
3785796c8dcSSimon Schubert   return 1;
3795796c8dcSSimon Schubert }
3805796c8dcSSimon Schubert 
3815796c8dcSSimon Schubert /* Write the byte at PTR into ADDR in the data cache.
3825796c8dcSSimon Schubert 
3835796c8dcSSimon Schubert    The caller is responsible for also promptly writing the data
3845796c8dcSSimon Schubert    through to target memory.
3855796c8dcSSimon Schubert 
3865796c8dcSSimon Schubert    If addr is not in cache, this function does nothing; writing to
3875796c8dcSSimon Schubert    an area of memory which wasn't present in the cache doesn't cause
3885796c8dcSSimon Schubert    it to be loaded in.
3895796c8dcSSimon Schubert 
3905796c8dcSSimon Schubert    Always return 1 (meaning success) to simplify dcache_xfer_memory.  */
3915796c8dcSSimon Schubert 
3925796c8dcSSimon Schubert static int
3935796c8dcSSimon Schubert dcache_poke_byte (DCACHE *dcache, CORE_ADDR addr, gdb_byte *ptr)
3945796c8dcSSimon Schubert {
3955796c8dcSSimon Schubert   struct dcache_block *db = dcache_hit (dcache, addr);
3965796c8dcSSimon Schubert 
3975796c8dcSSimon Schubert   if (db)
3985796c8dcSSimon Schubert     db->data[XFORM (addr)] = *ptr;
3995796c8dcSSimon Schubert 
4005796c8dcSSimon Schubert   return 1;
4015796c8dcSSimon Schubert }
4025796c8dcSSimon Schubert 
4035796c8dcSSimon Schubert static int
4045796c8dcSSimon Schubert dcache_splay_tree_compare (splay_tree_key a, splay_tree_key b)
4055796c8dcSSimon Schubert {
4065796c8dcSSimon Schubert   if (a > b)
4075796c8dcSSimon Schubert     return 1;
4085796c8dcSSimon Schubert   else if (a == b)
4095796c8dcSSimon Schubert     return 0;
4105796c8dcSSimon Schubert   else
4115796c8dcSSimon Schubert     return -1;
4125796c8dcSSimon Schubert }
4135796c8dcSSimon Schubert 
414*cf7f2e2dSJohn Marino /* Allocate and initialize a data cache.  */
4155796c8dcSSimon Schubert 
4165796c8dcSSimon Schubert DCACHE *
4175796c8dcSSimon Schubert dcache_init (void)
4185796c8dcSSimon Schubert {
4195796c8dcSSimon Schubert   DCACHE *dcache;
4205796c8dcSSimon Schubert 
4215796c8dcSSimon Schubert   dcache = (DCACHE *) xmalloc (sizeof (*dcache));
4225796c8dcSSimon Schubert 
4235796c8dcSSimon Schubert   dcache->tree = splay_tree_new (dcache_splay_tree_compare,
4245796c8dcSSimon Schubert 				 NULL,
4255796c8dcSSimon Schubert 				 NULL);
4265796c8dcSSimon Schubert 
4275796c8dcSSimon Schubert   dcache->oldest = NULL;
4285796c8dcSSimon Schubert   dcache->freelist = NULL;
4295796c8dcSSimon Schubert   dcache->size = 0;
4305796c8dcSSimon Schubert   dcache->ptid = null_ptid;
4315796c8dcSSimon Schubert   last_cache = dcache;
4325796c8dcSSimon Schubert 
4335796c8dcSSimon Schubert   return dcache;
4345796c8dcSSimon Schubert }
4355796c8dcSSimon Schubert 
436*cf7f2e2dSJohn Marino /* BLOCK_FUNC routine for dcache_free.  */
437*cf7f2e2dSJohn Marino 
438*cf7f2e2dSJohn Marino static void
439*cf7f2e2dSJohn Marino free_block (struct dcache_block *block, void *param)
440*cf7f2e2dSJohn Marino {
441*cf7f2e2dSJohn Marino   free (block);
442*cf7f2e2dSJohn Marino }
443*cf7f2e2dSJohn Marino 
4445796c8dcSSimon Schubert /* Free a data cache.  */
4455796c8dcSSimon Schubert 
4465796c8dcSSimon Schubert void
4475796c8dcSSimon Schubert dcache_free (DCACHE *dcache)
4485796c8dcSSimon Schubert {
4495796c8dcSSimon Schubert   if (last_cache == dcache)
4505796c8dcSSimon Schubert     last_cache = NULL;
4515796c8dcSSimon Schubert 
4525796c8dcSSimon Schubert   splay_tree_delete (dcache->tree);
453*cf7f2e2dSJohn Marino   for_each_block (&dcache->oldest, free_block, NULL);
454*cf7f2e2dSJohn Marino   for_each_block (&dcache->freelist, free_block, NULL);
4555796c8dcSSimon Schubert   xfree (dcache);
4565796c8dcSSimon Schubert }
4575796c8dcSSimon Schubert 
4585796c8dcSSimon Schubert /* Read or write LEN bytes from inferior memory at MEMADDR, transferring
4595796c8dcSSimon Schubert    to or from debugger address MYADDR.  Write to inferior if SHOULD_WRITE is
4605796c8dcSSimon Schubert    nonzero.
4615796c8dcSSimon Schubert 
462*cf7f2e2dSJohn Marino    Return the number of bytes actually transfered, or -1 if the
463*cf7f2e2dSJohn Marino    transfer is not supported or otherwise fails.  Return of a non-negative
464*cf7f2e2dSJohn Marino    value less than LEN indicates that no further transfer is possible.
465*cf7f2e2dSJohn Marino    NOTE: This is different than the to_xfer_partial interface, in which
466*cf7f2e2dSJohn Marino    positive values less than LEN mean further transfers may be possible.  */
4675796c8dcSSimon Schubert 
4685796c8dcSSimon Schubert int
4695796c8dcSSimon Schubert dcache_xfer_memory (struct target_ops *ops, DCACHE *dcache,
4705796c8dcSSimon Schubert 		    CORE_ADDR memaddr, gdb_byte *myaddr,
4715796c8dcSSimon Schubert 		    int len, int should_write)
4725796c8dcSSimon Schubert {
4735796c8dcSSimon Schubert   int i;
4745796c8dcSSimon Schubert   int res;
4755796c8dcSSimon Schubert   int (*xfunc) (DCACHE *dcache, CORE_ADDR addr, gdb_byte *ptr);
476*cf7f2e2dSJohn Marino 
4775796c8dcSSimon Schubert   xfunc = should_write ? dcache_poke_byte : dcache_peek_byte;
4785796c8dcSSimon Schubert 
4795796c8dcSSimon Schubert   /* If this is a different inferior from what we've recorded,
4805796c8dcSSimon Schubert      flush the cache.  */
4815796c8dcSSimon Schubert 
4825796c8dcSSimon Schubert   if (! ptid_equal (inferior_ptid, dcache->ptid))
4835796c8dcSSimon Schubert     {
4845796c8dcSSimon Schubert       dcache_invalidate (dcache);
4855796c8dcSSimon Schubert       dcache->ptid = inferior_ptid;
4865796c8dcSSimon Schubert     }
4875796c8dcSSimon Schubert 
4885796c8dcSSimon Schubert   /* Do write-through first, so that if it fails, we don't write to
4895796c8dcSSimon Schubert      the cache at all.  */
4905796c8dcSSimon Schubert 
4915796c8dcSSimon Schubert   if (should_write)
4925796c8dcSSimon Schubert     {
4935796c8dcSSimon Schubert       res = target_write (ops, TARGET_OBJECT_RAW_MEMORY,
4945796c8dcSSimon Schubert 			  NULL, myaddr, memaddr, len);
4955796c8dcSSimon Schubert       if (res <= 0)
4965796c8dcSSimon Schubert 	return res;
4975796c8dcSSimon Schubert       /* Update LEN to what was actually written.  */
4985796c8dcSSimon Schubert       len = res;
4995796c8dcSSimon Schubert     }
5005796c8dcSSimon Schubert 
5015796c8dcSSimon Schubert   for (i = 0; i < len; i++)
5025796c8dcSSimon Schubert     {
5035796c8dcSSimon Schubert       if (!xfunc (dcache, memaddr + i, myaddr + i))
5045796c8dcSSimon Schubert 	{
5055796c8dcSSimon Schubert 	  /* That failed.  Discard its cache line so we don't have a
5065796c8dcSSimon Schubert 	     partially read line.  */
5075796c8dcSSimon Schubert 	  dcache_invalidate_line (dcache, memaddr + i);
5085796c8dcSSimon Schubert 	  /* If we're writing, we still wrote LEN bytes.  */
5095796c8dcSSimon Schubert 	  if (should_write)
5105796c8dcSSimon Schubert 	    return len;
5115796c8dcSSimon Schubert 	  else
5125796c8dcSSimon Schubert 	    return i;
5135796c8dcSSimon Schubert 	}
5145796c8dcSSimon Schubert     }
5155796c8dcSSimon Schubert 
5165796c8dcSSimon Schubert   return len;
5175796c8dcSSimon Schubert }
5185796c8dcSSimon Schubert 
5195796c8dcSSimon Schubert /* FIXME: There would be some benefit to making the cache write-back and
5205796c8dcSSimon Schubert    moving the writeback operation to a higher layer, as it could occur
5215796c8dcSSimon Schubert    after a sequence of smaller writes have been completed (as when a stack
5225796c8dcSSimon Schubert    frame is constructed for an inferior function call).  Note that only
5235796c8dcSSimon Schubert    moving it up one level to target_xfer_memory[_partial]() is not
5245796c8dcSSimon Schubert    sufficient since we want to coalesce memory transfers that are
5255796c8dcSSimon Schubert    "logically" connected but not actually a single call to one of the
5265796c8dcSSimon Schubert    memory transfer functions.  */
5275796c8dcSSimon Schubert 
5285796c8dcSSimon Schubert /* Just update any cache lines which are already present.  This is called
5295796c8dcSSimon Schubert    by memory_xfer_partial in cases where the access would otherwise not go
5305796c8dcSSimon Schubert    through the cache.  */
5315796c8dcSSimon Schubert 
5325796c8dcSSimon Schubert void
5335796c8dcSSimon Schubert dcache_update (DCACHE *dcache, CORE_ADDR memaddr, gdb_byte *myaddr, int len)
5345796c8dcSSimon Schubert {
5355796c8dcSSimon Schubert   int i;
536*cf7f2e2dSJohn Marino 
5375796c8dcSSimon Schubert   for (i = 0; i < len; i++)
5385796c8dcSSimon Schubert     dcache_poke_byte (dcache, memaddr + i, myaddr + i);
5395796c8dcSSimon Schubert }
5405796c8dcSSimon Schubert 
5415796c8dcSSimon Schubert static void
5425796c8dcSSimon Schubert dcache_print_line (int index)
5435796c8dcSSimon Schubert {
5445796c8dcSSimon Schubert   splay_tree_node n;
5455796c8dcSSimon Schubert   struct dcache_block *db;
5465796c8dcSSimon Schubert   int i, j;
5475796c8dcSSimon Schubert 
5485796c8dcSSimon Schubert   if (!last_cache)
5495796c8dcSSimon Schubert     {
5505796c8dcSSimon Schubert       printf_filtered (_("No data cache available.\n"));
5515796c8dcSSimon Schubert       return;
5525796c8dcSSimon Schubert     }
5535796c8dcSSimon Schubert 
5545796c8dcSSimon Schubert   n = splay_tree_min (last_cache->tree);
5555796c8dcSSimon Schubert 
5565796c8dcSSimon Schubert   for (i = index; i > 0; --i)
5575796c8dcSSimon Schubert     {
5585796c8dcSSimon Schubert       if (!n)
5595796c8dcSSimon Schubert 	break;
5605796c8dcSSimon Schubert       n = splay_tree_successor (last_cache->tree, n->key);
5615796c8dcSSimon Schubert     }
5625796c8dcSSimon Schubert 
5635796c8dcSSimon Schubert   if (!n)
5645796c8dcSSimon Schubert     {
5655796c8dcSSimon Schubert       printf_filtered (_("No such cache line exists.\n"));
5665796c8dcSSimon Schubert       return;
5675796c8dcSSimon Schubert     }
5685796c8dcSSimon Schubert 
5695796c8dcSSimon Schubert   db = (struct dcache_block *) n->value;
5705796c8dcSSimon Schubert 
5715796c8dcSSimon Schubert   printf_filtered (_("Line %d: address %s [%d hits]\n"),
5725796c8dcSSimon Schubert 		   index, paddress (target_gdbarch, db->addr), db->refs);
5735796c8dcSSimon Schubert 
5745796c8dcSSimon Schubert   for (j = 0; j < LINE_SIZE; j++)
5755796c8dcSSimon Schubert     {
5765796c8dcSSimon Schubert       printf_filtered ("%02x ", db->data[j]);
5775796c8dcSSimon Schubert 
5785796c8dcSSimon Schubert       /* Print a newline every 16 bytes (48 characters) */
5795796c8dcSSimon Schubert       if ((j % 16 == 15) && (j != LINE_SIZE - 1))
5805796c8dcSSimon Schubert 	printf_filtered ("\n");
5815796c8dcSSimon Schubert     }
5825796c8dcSSimon Schubert   printf_filtered ("\n");
5835796c8dcSSimon Schubert }
5845796c8dcSSimon Schubert 
5855796c8dcSSimon Schubert static void
5865796c8dcSSimon Schubert dcache_info (char *exp, int tty)
5875796c8dcSSimon Schubert {
5885796c8dcSSimon Schubert   splay_tree_node n;
589*cf7f2e2dSJohn Marino   int i, refcount;
5905796c8dcSSimon Schubert 
5915796c8dcSSimon Schubert   if (exp)
5925796c8dcSSimon Schubert     {
5935796c8dcSSimon Schubert       char *linestart;
594*cf7f2e2dSJohn Marino 
5955796c8dcSSimon Schubert       i = strtol (exp, &linestart, 10);
5965796c8dcSSimon Schubert       if (linestart == exp || i < 0)
5975796c8dcSSimon Schubert 	{
5985796c8dcSSimon Schubert 	  printf_filtered (_("Usage: info dcache [linenumber]\n"));
5995796c8dcSSimon Schubert           return;
6005796c8dcSSimon Schubert 	}
6015796c8dcSSimon Schubert 
6025796c8dcSSimon Schubert       dcache_print_line (i);
6035796c8dcSSimon Schubert       return;
6045796c8dcSSimon Schubert     }
6055796c8dcSSimon Schubert 
6065796c8dcSSimon Schubert   printf_filtered (_("Dcache line width %d, maximum size %d\n"),
6075796c8dcSSimon Schubert 		   LINE_SIZE, DCACHE_SIZE);
6085796c8dcSSimon Schubert 
6095796c8dcSSimon Schubert   if (!last_cache || ptid_equal (last_cache->ptid, null_ptid))
6105796c8dcSSimon Schubert     {
6115796c8dcSSimon Schubert       printf_filtered (_("No data cache available.\n"));
6125796c8dcSSimon Schubert       return;
6135796c8dcSSimon Schubert     }
6145796c8dcSSimon Schubert 
6155796c8dcSSimon Schubert   printf_filtered (_("Contains data for %s\n"),
6165796c8dcSSimon Schubert 		   target_pid_to_str (last_cache->ptid));
6175796c8dcSSimon Schubert 
6185796c8dcSSimon Schubert   refcount = 0;
6195796c8dcSSimon Schubert 
6205796c8dcSSimon Schubert   n = splay_tree_min (last_cache->tree);
6215796c8dcSSimon Schubert   i = 0;
6225796c8dcSSimon Schubert 
6235796c8dcSSimon Schubert   while (n)
6245796c8dcSSimon Schubert     {
6255796c8dcSSimon Schubert       struct dcache_block *db = (struct dcache_block *) n->value;
6265796c8dcSSimon Schubert 
6275796c8dcSSimon Schubert       printf_filtered (_("Line %d: address %s [%d hits]\n"),
6285796c8dcSSimon Schubert 		       i, paddress (target_gdbarch, db->addr), db->refs);
6295796c8dcSSimon Schubert       i++;
6305796c8dcSSimon Schubert       refcount += db->refs;
6315796c8dcSSimon Schubert 
6325796c8dcSSimon Schubert       n = splay_tree_successor (last_cache->tree, n->key);
6335796c8dcSSimon Schubert     }
6345796c8dcSSimon Schubert 
6355796c8dcSSimon Schubert   printf_filtered (_("Cache state: %d active lines, %d hits\n"), i, refcount);
6365796c8dcSSimon Schubert }
6375796c8dcSSimon Schubert 
6385796c8dcSSimon Schubert void
6395796c8dcSSimon Schubert _initialize_dcache (void)
6405796c8dcSSimon Schubert {
6415796c8dcSSimon Schubert   add_setshow_boolean_cmd ("remotecache", class_support,
6425796c8dcSSimon Schubert 			   &dcache_enabled_p, _("\
6435796c8dcSSimon Schubert Set cache use for remote targets."), _("\
6445796c8dcSSimon Schubert Show cache use for remote targets."), _("\
6455796c8dcSSimon Schubert This used to enable the data cache for remote targets.  The cache\n\
6465796c8dcSSimon Schubert functionality is now controlled by the memory region system and the\n\
6475796c8dcSSimon Schubert \"stack-cache\" flag; \"remotecache\" now does nothing and\n\
6485796c8dcSSimon Schubert exists only for compatibility reasons."),
6495796c8dcSSimon Schubert 			   NULL,
6505796c8dcSSimon Schubert 			   show_dcache_enabled_p,
6515796c8dcSSimon Schubert 			   &setlist, &showlist);
6525796c8dcSSimon Schubert 
6535796c8dcSSimon Schubert   add_info ("dcache", dcache_info,
6545796c8dcSSimon Schubert 	    _("\
6555796c8dcSSimon Schubert Print information on the dcache performance.\n\
6565796c8dcSSimon Schubert With no arguments, this command prints the cache configuration and a\n\
6575796c8dcSSimon Schubert summary of each line in the cache.  Use \"info dcache <lineno> to dump\"\n\
6585796c8dcSSimon Schubert the contents of a given line."));
6595796c8dcSSimon Schubert }
660