15796c8dcSSimon Schubert /* Caching code for GDB, the GNU debugger.
25796c8dcSSimon Schubert
3*ef5ccd6cSJohn Marino Copyright (C) 1992-2013 Free Software Foundation, Inc.
45796c8dcSSimon Schubert
55796c8dcSSimon Schubert This file is part of GDB.
65796c8dcSSimon Schubert
75796c8dcSSimon Schubert This program is free software; you can redistribute it and/or modify
85796c8dcSSimon Schubert it under the terms of the GNU General Public License as published by
95796c8dcSSimon Schubert the Free Software Foundation; either version 3 of the License, or
105796c8dcSSimon Schubert (at your option) any later version.
115796c8dcSSimon Schubert
125796c8dcSSimon Schubert This program is distributed in the hope that it will be useful,
135796c8dcSSimon Schubert but WITHOUT ANY WARRANTY; without even the implied warranty of
145796c8dcSSimon Schubert MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
155796c8dcSSimon Schubert GNU General Public License for more details.
165796c8dcSSimon Schubert
175796c8dcSSimon Schubert You should have received a copy of the GNU General Public License
185796c8dcSSimon Schubert along with this program. If not, see <http://www.gnu.org/licenses/>. */
195796c8dcSSimon Schubert
205796c8dcSSimon Schubert #include "defs.h"
215796c8dcSSimon Schubert #include "dcache.h"
225796c8dcSSimon Schubert #include "gdbcmd.h"
235796c8dcSSimon Schubert #include "gdb_string.h"
245796c8dcSSimon Schubert #include "gdbcore.h"
255796c8dcSSimon Schubert #include "target.h"
265796c8dcSSimon Schubert #include "inferior.h"
275796c8dcSSimon Schubert #include "splay-tree.h"
285796c8dcSSimon Schubert
29a45ae5f8SJohn Marino /* Commands with a prefix of `{set,show} dcache'. */
30a45ae5f8SJohn Marino static struct cmd_list_element *dcache_set_list = NULL;
31a45ae5f8SJohn Marino static struct cmd_list_element *dcache_show_list = NULL;
32a45ae5f8SJohn Marino
335796c8dcSSimon Schubert /* The data cache could lead to incorrect results because it doesn't
345796c8dcSSimon Schubert know about volatile variables, thus making it impossible to debug
355796c8dcSSimon Schubert functions which use memory mapped I/O devices. Set the nocache
365796c8dcSSimon Schubert memory region attribute in those cases.
375796c8dcSSimon Schubert
385796c8dcSSimon Schubert In general the dcache speeds up performance. Some speed improvement
395796c8dcSSimon Schubert comes from the actual caching mechanism, but the major gain is in
405796c8dcSSimon Schubert the reduction of the remote protocol overhead; instead of reading
415796c8dcSSimon Schubert or writing a large area of memory in 4 byte requests, the cache
425796c8dcSSimon Schubert bundles up the requests into LINE_SIZE chunks, reducing overhead
435796c8dcSSimon Schubert significantly. This is most useful when accessing a large amount
445796c8dcSSimon Schubert of data, such as when performing a backtrace.
455796c8dcSSimon Schubert
465796c8dcSSimon Schubert The cache is a splay tree along with a linked list for replacement.
47cf7f2e2dSJohn Marino Each block caches a LINE_SIZE area of memory. Within each line we
48cf7f2e2dSJohn Marino remember the address of the line (which must be a multiple of
49cf7f2e2dSJohn Marino LINE_SIZE) and the actual data block.
505796c8dcSSimon Schubert
515796c8dcSSimon Schubert Lines are only allocated as needed, so DCACHE_SIZE really specifies the
525796c8dcSSimon Schubert *maximum* number of lines in the cache.
535796c8dcSSimon Schubert
545796c8dcSSimon Schubert At present, the cache is write-through rather than writeback: as soon
555796c8dcSSimon Schubert as data is written to the cache, it is also immediately written to
565796c8dcSSimon Schubert the target. Therefore, cache lines are never "dirty". Whether a given
575796c8dcSSimon Schubert line is valid or not depends on where it is stored in the dcache_struct;
585796c8dcSSimon Schubert there is no per-block valid flag. */
595796c8dcSSimon Schubert
605796c8dcSSimon Schubert /* NOTE: Interaction of dcache and memory region attributes
615796c8dcSSimon Schubert
625796c8dcSSimon Schubert As there is no requirement that memory region attributes be aligned
635796c8dcSSimon Schubert to or be a multiple of the dcache page size, dcache_read_line() and
645796c8dcSSimon Schubert dcache_write_line() must break up the page by memory region. If a
655796c8dcSSimon Schubert chunk does not have the cache attribute set, an invalid memory type
665796c8dcSSimon Schubert is set, etc., then the chunk is skipped. Those chunks are handled
675796c8dcSSimon Schubert in target_xfer_memory() (or target_xfer_memory_partial()).
685796c8dcSSimon Schubert
695796c8dcSSimon Schubert This doesn't occur very often. The most common occurance is when
705796c8dcSSimon Schubert the last bit of the .text segment and the first bit of the .data
715796c8dcSSimon Schubert segment fall within the same dcache page with a ro/cacheable memory
725796c8dcSSimon Schubert region defined for the .text segment and a rw/non-cacheable memory
735796c8dcSSimon Schubert region defined for the .data segment. */
745796c8dcSSimon Schubert
755796c8dcSSimon Schubert /* The maximum number of lines stored. The total size of the cache is
765796c8dcSSimon Schubert equal to DCACHE_SIZE times LINE_SIZE. */
77a45ae5f8SJohn Marino #define DCACHE_DEFAULT_SIZE 4096
78a45ae5f8SJohn Marino static unsigned dcache_size = DCACHE_DEFAULT_SIZE;
795796c8dcSSimon Schubert
80a45ae5f8SJohn Marino /* The default size of a cache line. Smaller values reduce the time taken to
815796c8dcSSimon Schubert read a single byte and make the cache more granular, but increase
825796c8dcSSimon Schubert overhead and reduce the effectiveness of the cache as a prefetcher. */
83a45ae5f8SJohn Marino #define DCACHE_DEFAULT_LINE_SIZE 64
84a45ae5f8SJohn Marino static unsigned dcache_line_size = DCACHE_DEFAULT_LINE_SIZE;
855796c8dcSSimon Schubert
865796c8dcSSimon Schubert /* Each cache block holds LINE_SIZE bytes of data
875796c8dcSSimon Schubert starting at a multiple-of-LINE_SIZE address. */
885796c8dcSSimon Schubert
89a45ae5f8SJohn Marino #define LINE_SIZE_MASK(dcache) ((dcache->line_size - 1))
90a45ae5f8SJohn Marino #define XFORM(dcache, x) ((x) & LINE_SIZE_MASK (dcache))
91a45ae5f8SJohn Marino #define MASK(dcache, x) ((x) & ~LINE_SIZE_MASK (dcache))
925796c8dcSSimon Schubert
935796c8dcSSimon Schubert struct dcache_block
945796c8dcSSimon Schubert {
95c50c785cSJohn Marino /* For least-recently-allocated and free lists. */
96cf7f2e2dSJohn Marino struct dcache_block *prev;
97cf7f2e2dSJohn Marino struct dcache_block *next;
98cf7f2e2dSJohn Marino
995796c8dcSSimon Schubert CORE_ADDR addr; /* address of data */
1005796c8dcSSimon Schubert int refs; /* # hits */
101a45ae5f8SJohn Marino gdb_byte data[1]; /* line_size bytes at given address */
1025796c8dcSSimon Schubert };
1035796c8dcSSimon Schubert
1045796c8dcSSimon Schubert struct dcache_struct
1055796c8dcSSimon Schubert {
1065796c8dcSSimon Schubert splay_tree tree;
107c50c785cSJohn Marino struct dcache_block *oldest; /* least-recently-allocated list. */
1085796c8dcSSimon Schubert
109cf7f2e2dSJohn Marino /* The free list is maintained identically to OLDEST to simplify
110cf7f2e2dSJohn Marino the code: we only need one set of accessors. */
1115796c8dcSSimon Schubert struct dcache_block *freelist;
1125796c8dcSSimon Schubert
1135796c8dcSSimon Schubert /* The number of in-use lines in the cache. */
1145796c8dcSSimon Schubert int size;
115a45ae5f8SJohn Marino CORE_ADDR line_size; /* current line_size. */
1165796c8dcSSimon Schubert
1175796c8dcSSimon Schubert /* The ptid of last inferior to use cache or null_ptid. */
1185796c8dcSSimon Schubert ptid_t ptid;
1195796c8dcSSimon Schubert };
1205796c8dcSSimon Schubert
121cf7f2e2dSJohn Marino typedef void (block_func) (struct dcache_block *block, void *param);
1225796c8dcSSimon Schubert
123cf7f2e2dSJohn Marino static struct dcache_block *dcache_hit (DCACHE *dcache, CORE_ADDR addr);
1245796c8dcSSimon Schubert
1255796c8dcSSimon Schubert static int dcache_read_line (DCACHE *dcache, struct dcache_block *db);
1265796c8dcSSimon Schubert
1275796c8dcSSimon Schubert static struct dcache_block *dcache_alloc (DCACHE *dcache, CORE_ADDR addr);
1285796c8dcSSimon Schubert
1295796c8dcSSimon Schubert static void dcache_info (char *exp, int tty);
1305796c8dcSSimon Schubert
1315796c8dcSSimon Schubert void _initialize_dcache (void);
1325796c8dcSSimon Schubert
1335796c8dcSSimon Schubert static int dcache_enabled_p = 0; /* OBSOLETE */
1345796c8dcSSimon Schubert
1355796c8dcSSimon Schubert static void
show_dcache_enabled_p(struct ui_file * file,int from_tty,struct cmd_list_element * c,const char * value)1365796c8dcSSimon Schubert show_dcache_enabled_p (struct ui_file *file, int from_tty,
1375796c8dcSSimon Schubert struct cmd_list_element *c, const char *value)
1385796c8dcSSimon Schubert {
1395796c8dcSSimon Schubert fprintf_filtered (file, _("Deprecated remotecache flag is %s.\n"), value);
1405796c8dcSSimon Schubert }
1415796c8dcSSimon Schubert
142c50c785cSJohn Marino static DCACHE *last_cache; /* Used by info dcache. */
1435796c8dcSSimon Schubert
144cf7f2e2dSJohn Marino /* Add BLOCK to circular block list BLIST, behind the block at *BLIST.
145cf7f2e2dSJohn Marino *BLIST is not updated (unless it was previously NULL of course).
146cf7f2e2dSJohn Marino This is for the least-recently-allocated list's sake:
147cf7f2e2dSJohn Marino BLIST points to the oldest block.
148cf7f2e2dSJohn Marino ??? This makes for poor cache usage of the free list,
149cf7f2e2dSJohn Marino but is it measurable? */
150cf7f2e2dSJohn Marino
151cf7f2e2dSJohn Marino static void
append_block(struct dcache_block ** blist,struct dcache_block * block)152cf7f2e2dSJohn Marino append_block (struct dcache_block **blist, struct dcache_block *block)
153cf7f2e2dSJohn Marino {
154cf7f2e2dSJohn Marino if (*blist)
155cf7f2e2dSJohn Marino {
156cf7f2e2dSJohn Marino block->next = *blist;
157cf7f2e2dSJohn Marino block->prev = (*blist)->prev;
158cf7f2e2dSJohn Marino block->prev->next = block;
159cf7f2e2dSJohn Marino (*blist)->prev = block;
160cf7f2e2dSJohn Marino /* We don't update *BLIST here to maintain the invariant that for the
161cf7f2e2dSJohn Marino least-recently-allocated list *BLIST points to the oldest block. */
162cf7f2e2dSJohn Marino }
163cf7f2e2dSJohn Marino else
164cf7f2e2dSJohn Marino {
165cf7f2e2dSJohn Marino block->next = block;
166cf7f2e2dSJohn Marino block->prev = block;
167cf7f2e2dSJohn Marino *blist = block;
168cf7f2e2dSJohn Marino }
169cf7f2e2dSJohn Marino }
170cf7f2e2dSJohn Marino
171cf7f2e2dSJohn Marino /* Remove BLOCK from circular block list BLIST. */
172cf7f2e2dSJohn Marino
173cf7f2e2dSJohn Marino static void
remove_block(struct dcache_block ** blist,struct dcache_block * block)174cf7f2e2dSJohn Marino remove_block (struct dcache_block **blist, struct dcache_block *block)
175cf7f2e2dSJohn Marino {
176cf7f2e2dSJohn Marino if (block->next == block)
177cf7f2e2dSJohn Marino {
178cf7f2e2dSJohn Marino *blist = NULL;
179cf7f2e2dSJohn Marino }
180cf7f2e2dSJohn Marino else
181cf7f2e2dSJohn Marino {
182cf7f2e2dSJohn Marino block->next->prev = block->prev;
183cf7f2e2dSJohn Marino block->prev->next = block->next;
184cf7f2e2dSJohn Marino /* If we removed the block *BLIST points to, shift it to the next block
185cf7f2e2dSJohn Marino to maintain the invariant that for the least-recently-allocated list
186cf7f2e2dSJohn Marino *BLIST points to the oldest block. */
187cf7f2e2dSJohn Marino if (*blist == block)
188cf7f2e2dSJohn Marino *blist = block->next;
189cf7f2e2dSJohn Marino }
190cf7f2e2dSJohn Marino }
191cf7f2e2dSJohn Marino
192cf7f2e2dSJohn Marino /* Iterate over all elements in BLIST, calling FUNC.
193cf7f2e2dSJohn Marino PARAM is passed to FUNC.
194cf7f2e2dSJohn Marino FUNC may remove the block it's passed, but only that block. */
195cf7f2e2dSJohn Marino
196cf7f2e2dSJohn Marino static void
for_each_block(struct dcache_block ** blist,block_func * func,void * param)197cf7f2e2dSJohn Marino for_each_block (struct dcache_block **blist, block_func *func, void *param)
198cf7f2e2dSJohn Marino {
199cf7f2e2dSJohn Marino struct dcache_block *db;
200cf7f2e2dSJohn Marino
201cf7f2e2dSJohn Marino if (*blist == NULL)
202cf7f2e2dSJohn Marino return;
203cf7f2e2dSJohn Marino
204cf7f2e2dSJohn Marino db = *blist;
205cf7f2e2dSJohn Marino do
206cf7f2e2dSJohn Marino {
207cf7f2e2dSJohn Marino struct dcache_block *next = db->next;
208cf7f2e2dSJohn Marino
209cf7f2e2dSJohn Marino func (db, param);
210cf7f2e2dSJohn Marino db = next;
211cf7f2e2dSJohn Marino }
212cf7f2e2dSJohn Marino while (*blist && db != *blist);
213cf7f2e2dSJohn Marino }
214cf7f2e2dSJohn Marino
215a45ae5f8SJohn Marino /* BLOCK_FUNC routine for dcache_free. */
216a45ae5f8SJohn Marino
217a45ae5f8SJohn Marino static void
free_block(struct dcache_block * block,void * param)218a45ae5f8SJohn Marino free_block (struct dcache_block *block, void *param)
219a45ae5f8SJohn Marino {
220a45ae5f8SJohn Marino xfree (block);
221a45ae5f8SJohn Marino }
222a45ae5f8SJohn Marino
223a45ae5f8SJohn Marino /* Free a data cache. */
224a45ae5f8SJohn Marino
225a45ae5f8SJohn Marino void
dcache_free(DCACHE * dcache)226a45ae5f8SJohn Marino dcache_free (DCACHE *dcache)
227a45ae5f8SJohn Marino {
228a45ae5f8SJohn Marino if (last_cache == dcache)
229a45ae5f8SJohn Marino last_cache = NULL;
230a45ae5f8SJohn Marino
231a45ae5f8SJohn Marino splay_tree_delete (dcache->tree);
232a45ae5f8SJohn Marino for_each_block (&dcache->oldest, free_block, NULL);
233a45ae5f8SJohn Marino for_each_block (&dcache->freelist, free_block, NULL);
234a45ae5f8SJohn Marino xfree (dcache);
235a45ae5f8SJohn Marino }
236a45ae5f8SJohn Marino
237a45ae5f8SJohn Marino
238cf7f2e2dSJohn Marino /* BLOCK_FUNC function for dcache_invalidate.
239cf7f2e2dSJohn Marino This doesn't remove the block from the oldest list on purpose.
240cf7f2e2dSJohn Marino dcache_invalidate will do it later. */
241cf7f2e2dSJohn Marino
242cf7f2e2dSJohn Marino static void
invalidate_block(struct dcache_block * block,void * param)243cf7f2e2dSJohn Marino invalidate_block (struct dcache_block *block, void *param)
244cf7f2e2dSJohn Marino {
245cf7f2e2dSJohn Marino DCACHE *dcache = (DCACHE *) param;
246cf7f2e2dSJohn Marino
247cf7f2e2dSJohn Marino splay_tree_remove (dcache->tree, (splay_tree_key) block->addr);
248cf7f2e2dSJohn Marino append_block (&dcache->freelist, block);
249cf7f2e2dSJohn Marino }
250cf7f2e2dSJohn Marino
2515796c8dcSSimon Schubert /* Free all the data cache blocks, thus discarding all cached data. */
2525796c8dcSSimon Schubert
2535796c8dcSSimon Schubert void
dcache_invalidate(DCACHE * dcache)2545796c8dcSSimon Schubert dcache_invalidate (DCACHE *dcache)
2555796c8dcSSimon Schubert {
256cf7f2e2dSJohn Marino for_each_block (&dcache->oldest, invalidate_block, dcache);
2575796c8dcSSimon Schubert
2585796c8dcSSimon Schubert dcache->oldest = NULL;
2595796c8dcSSimon Schubert dcache->size = 0;
2605796c8dcSSimon Schubert dcache->ptid = null_ptid;
261a45ae5f8SJohn Marino
262a45ae5f8SJohn Marino if (dcache->line_size != dcache_line_size)
263a45ae5f8SJohn Marino {
264a45ae5f8SJohn Marino /* We've been asked to use a different line size.
265a45ae5f8SJohn Marino All of our freelist blocks are now the wrong size, so free them. */
266a45ae5f8SJohn Marino
267a45ae5f8SJohn Marino for_each_block (&dcache->freelist, free_block, dcache);
268a45ae5f8SJohn Marino dcache->freelist = NULL;
269a45ae5f8SJohn Marino dcache->line_size = dcache_line_size;
270a45ae5f8SJohn Marino }
2715796c8dcSSimon Schubert }
2725796c8dcSSimon Schubert
2735796c8dcSSimon Schubert /* Invalidate the line associated with ADDR. */
2745796c8dcSSimon Schubert
2755796c8dcSSimon Schubert static void
dcache_invalidate_line(DCACHE * dcache,CORE_ADDR addr)2765796c8dcSSimon Schubert dcache_invalidate_line (DCACHE *dcache, CORE_ADDR addr)
2775796c8dcSSimon Schubert {
2785796c8dcSSimon Schubert struct dcache_block *db = dcache_hit (dcache, addr);
2795796c8dcSSimon Schubert
2805796c8dcSSimon Schubert if (db)
2815796c8dcSSimon Schubert {
2825796c8dcSSimon Schubert splay_tree_remove (dcache->tree, (splay_tree_key) db->addr);
283cf7f2e2dSJohn Marino remove_block (&dcache->oldest, db);
284cf7f2e2dSJohn Marino append_block (&dcache->freelist, db);
2855796c8dcSSimon Schubert --dcache->size;
2865796c8dcSSimon Schubert }
2875796c8dcSSimon Schubert }
2885796c8dcSSimon Schubert
2895796c8dcSSimon Schubert /* If addr is present in the dcache, return the address of the block
290cf7f2e2dSJohn Marino containing it. Otherwise return NULL. */
2915796c8dcSSimon Schubert
2925796c8dcSSimon Schubert static struct dcache_block *
dcache_hit(DCACHE * dcache,CORE_ADDR addr)2935796c8dcSSimon Schubert dcache_hit (DCACHE *dcache, CORE_ADDR addr)
2945796c8dcSSimon Schubert {
2955796c8dcSSimon Schubert struct dcache_block *db;
2965796c8dcSSimon Schubert
2975796c8dcSSimon Schubert splay_tree_node node = splay_tree_lookup (dcache->tree,
298a45ae5f8SJohn Marino (splay_tree_key) MASK (dcache, addr));
2995796c8dcSSimon Schubert
3005796c8dcSSimon Schubert if (!node)
3015796c8dcSSimon Schubert return NULL;
3025796c8dcSSimon Schubert
3035796c8dcSSimon Schubert db = (struct dcache_block *) node->value;
3045796c8dcSSimon Schubert db->refs++;
3055796c8dcSSimon Schubert return db;
3065796c8dcSSimon Schubert }
3075796c8dcSSimon Schubert
308cf7f2e2dSJohn Marino /* Fill a cache line from target memory.
309cf7f2e2dSJohn Marino The result is 1 for success, 0 if the (entire) cache line
310cf7f2e2dSJohn Marino wasn't readable. */
3115796c8dcSSimon Schubert
3125796c8dcSSimon Schubert static int
dcache_read_line(DCACHE * dcache,struct dcache_block * db)3135796c8dcSSimon Schubert dcache_read_line (DCACHE *dcache, struct dcache_block *db)
3145796c8dcSSimon Schubert {
3155796c8dcSSimon Schubert CORE_ADDR memaddr;
3165796c8dcSSimon Schubert gdb_byte *myaddr;
3175796c8dcSSimon Schubert int len;
3185796c8dcSSimon Schubert int res;
3195796c8dcSSimon Schubert int reg_len;
3205796c8dcSSimon Schubert struct mem_region *region;
3215796c8dcSSimon Schubert
322a45ae5f8SJohn Marino len = dcache->line_size;
3235796c8dcSSimon Schubert memaddr = db->addr;
3245796c8dcSSimon Schubert myaddr = db->data;
3255796c8dcSSimon Schubert
3265796c8dcSSimon Schubert while (len > 0)
3275796c8dcSSimon Schubert {
3285796c8dcSSimon Schubert /* Don't overrun if this block is right at the end of the region. */
3295796c8dcSSimon Schubert region = lookup_mem_region (memaddr);
3305796c8dcSSimon Schubert if (region->hi == 0 || memaddr + len < region->hi)
3315796c8dcSSimon Schubert reg_len = len;
3325796c8dcSSimon Schubert else
3335796c8dcSSimon Schubert reg_len = region->hi - memaddr;
3345796c8dcSSimon Schubert
3355796c8dcSSimon Schubert /* Skip non-readable regions. The cache attribute can be ignored,
3365796c8dcSSimon Schubert since we may be loading this for a stack access. */
3375796c8dcSSimon Schubert if (region->attrib.mode == MEM_WO)
3385796c8dcSSimon Schubert {
3395796c8dcSSimon Schubert memaddr += reg_len;
3405796c8dcSSimon Schubert myaddr += reg_len;
3415796c8dcSSimon Schubert len -= reg_len;
3425796c8dcSSimon Schubert continue;
3435796c8dcSSimon Schubert }
3445796c8dcSSimon Schubert
3455796c8dcSSimon Schubert res = target_read (¤t_target, TARGET_OBJECT_RAW_MEMORY,
3465796c8dcSSimon Schubert NULL, myaddr, memaddr, reg_len);
3475796c8dcSSimon Schubert if (res < reg_len)
3485796c8dcSSimon Schubert return 0;
3495796c8dcSSimon Schubert
3505796c8dcSSimon Schubert memaddr += res;
3515796c8dcSSimon Schubert myaddr += res;
3525796c8dcSSimon Schubert len -= res;
3535796c8dcSSimon Schubert }
3545796c8dcSSimon Schubert
3555796c8dcSSimon Schubert return 1;
3565796c8dcSSimon Schubert }
3575796c8dcSSimon Schubert
3585796c8dcSSimon Schubert /* Get a free cache block, put or keep it on the valid list,
3595796c8dcSSimon Schubert and return its address. */
3605796c8dcSSimon Schubert
3615796c8dcSSimon Schubert static struct dcache_block *
dcache_alloc(DCACHE * dcache,CORE_ADDR addr)3625796c8dcSSimon Schubert dcache_alloc (DCACHE *dcache, CORE_ADDR addr)
3635796c8dcSSimon Schubert {
3645796c8dcSSimon Schubert struct dcache_block *db;
3655796c8dcSSimon Schubert
366a45ae5f8SJohn Marino if (dcache->size >= dcache_size)
3675796c8dcSSimon Schubert {
368cf7f2e2dSJohn Marino /* Evict the least recently allocated line. */
3695796c8dcSSimon Schubert db = dcache->oldest;
370cf7f2e2dSJohn Marino remove_block (&dcache->oldest, db);
3715796c8dcSSimon Schubert
3725796c8dcSSimon Schubert splay_tree_remove (dcache->tree, (splay_tree_key) db->addr);
3735796c8dcSSimon Schubert }
3745796c8dcSSimon Schubert else
3755796c8dcSSimon Schubert {
3765796c8dcSSimon Schubert db = dcache->freelist;
3775796c8dcSSimon Schubert if (db)
378cf7f2e2dSJohn Marino remove_block (&dcache->freelist, db);
3795796c8dcSSimon Schubert else
380a45ae5f8SJohn Marino db = xmalloc (offsetof (struct dcache_block, data) +
381a45ae5f8SJohn Marino dcache->line_size);
3825796c8dcSSimon Schubert
3835796c8dcSSimon Schubert dcache->size++;
3845796c8dcSSimon Schubert }
3855796c8dcSSimon Schubert
386a45ae5f8SJohn Marino db->addr = MASK (dcache, addr);
3875796c8dcSSimon Schubert db->refs = 0;
3885796c8dcSSimon Schubert
389cf7f2e2dSJohn Marino /* Put DB at the end of the list, it's the newest. */
390cf7f2e2dSJohn Marino append_block (&dcache->oldest, db);
3915796c8dcSSimon Schubert
3925796c8dcSSimon Schubert splay_tree_insert (dcache->tree, (splay_tree_key) db->addr,
3935796c8dcSSimon Schubert (splay_tree_value) db);
3945796c8dcSSimon Schubert
3955796c8dcSSimon Schubert return db;
3965796c8dcSSimon Schubert }
3975796c8dcSSimon Schubert
398cf7f2e2dSJohn Marino /* Using the data cache DCACHE, store in *PTR the contents of the byte at
3995796c8dcSSimon Schubert address ADDR in the remote machine.
4005796c8dcSSimon Schubert
4015796c8dcSSimon Schubert Returns 1 for success, 0 for error. */
4025796c8dcSSimon Schubert
4035796c8dcSSimon Schubert static int
dcache_peek_byte(DCACHE * dcache,CORE_ADDR addr,gdb_byte * ptr)4045796c8dcSSimon Schubert dcache_peek_byte (DCACHE *dcache, CORE_ADDR addr, gdb_byte *ptr)
4055796c8dcSSimon Schubert {
4065796c8dcSSimon Schubert struct dcache_block *db = dcache_hit (dcache, addr);
4075796c8dcSSimon Schubert
4085796c8dcSSimon Schubert if (!db)
4095796c8dcSSimon Schubert {
4105796c8dcSSimon Schubert db = dcache_alloc (dcache, addr);
4115796c8dcSSimon Schubert
4125796c8dcSSimon Schubert if (!dcache_read_line (dcache, db))
4135796c8dcSSimon Schubert return 0;
4145796c8dcSSimon Schubert }
4155796c8dcSSimon Schubert
416a45ae5f8SJohn Marino *ptr = db->data[XFORM (dcache, addr)];
4175796c8dcSSimon Schubert return 1;
4185796c8dcSSimon Schubert }
4195796c8dcSSimon Schubert
4205796c8dcSSimon Schubert /* Write the byte at PTR into ADDR in the data cache.
4215796c8dcSSimon Schubert
4225796c8dcSSimon Schubert The caller is responsible for also promptly writing the data
4235796c8dcSSimon Schubert through to target memory.
4245796c8dcSSimon Schubert
4255796c8dcSSimon Schubert If addr is not in cache, this function does nothing; writing to
4265796c8dcSSimon Schubert an area of memory which wasn't present in the cache doesn't cause
4275796c8dcSSimon Schubert it to be loaded in.
4285796c8dcSSimon Schubert
4295796c8dcSSimon Schubert Always return 1 (meaning success) to simplify dcache_xfer_memory. */
4305796c8dcSSimon Schubert
4315796c8dcSSimon Schubert static int
dcache_poke_byte(DCACHE * dcache,CORE_ADDR addr,gdb_byte * ptr)4325796c8dcSSimon Schubert dcache_poke_byte (DCACHE *dcache, CORE_ADDR addr, gdb_byte *ptr)
4335796c8dcSSimon Schubert {
4345796c8dcSSimon Schubert struct dcache_block *db = dcache_hit (dcache, addr);
4355796c8dcSSimon Schubert
4365796c8dcSSimon Schubert if (db)
437a45ae5f8SJohn Marino db->data[XFORM (dcache, addr)] = *ptr;
4385796c8dcSSimon Schubert
4395796c8dcSSimon Schubert return 1;
4405796c8dcSSimon Schubert }
4415796c8dcSSimon Schubert
4425796c8dcSSimon Schubert static int
dcache_splay_tree_compare(splay_tree_key a,splay_tree_key b)4435796c8dcSSimon Schubert dcache_splay_tree_compare (splay_tree_key a, splay_tree_key b)
4445796c8dcSSimon Schubert {
4455796c8dcSSimon Schubert if (a > b)
4465796c8dcSSimon Schubert return 1;
4475796c8dcSSimon Schubert else if (a == b)
4485796c8dcSSimon Schubert return 0;
4495796c8dcSSimon Schubert else
4505796c8dcSSimon Schubert return -1;
4515796c8dcSSimon Schubert }
4525796c8dcSSimon Schubert
453cf7f2e2dSJohn Marino /* Allocate and initialize a data cache. */
4545796c8dcSSimon Schubert
4555796c8dcSSimon Schubert DCACHE *
dcache_init(void)4565796c8dcSSimon Schubert dcache_init (void)
4575796c8dcSSimon Schubert {
4585796c8dcSSimon Schubert DCACHE *dcache;
4595796c8dcSSimon Schubert
4605796c8dcSSimon Schubert dcache = (DCACHE *) xmalloc (sizeof (*dcache));
4615796c8dcSSimon Schubert
4625796c8dcSSimon Schubert dcache->tree = splay_tree_new (dcache_splay_tree_compare,
4635796c8dcSSimon Schubert NULL,
4645796c8dcSSimon Schubert NULL);
4655796c8dcSSimon Schubert
4665796c8dcSSimon Schubert dcache->oldest = NULL;
4675796c8dcSSimon Schubert dcache->freelist = NULL;
4685796c8dcSSimon Schubert dcache->size = 0;
469a45ae5f8SJohn Marino dcache->line_size = dcache_line_size;
4705796c8dcSSimon Schubert dcache->ptid = null_ptid;
4715796c8dcSSimon Schubert last_cache = dcache;
4725796c8dcSSimon Schubert
4735796c8dcSSimon Schubert return dcache;
4745796c8dcSSimon Schubert }
4755796c8dcSSimon Schubert
4765796c8dcSSimon Schubert
4775796c8dcSSimon Schubert /* Read or write LEN bytes from inferior memory at MEMADDR, transferring
4785796c8dcSSimon Schubert to or from debugger address MYADDR. Write to inferior if SHOULD_WRITE is
4795796c8dcSSimon Schubert nonzero.
4805796c8dcSSimon Schubert
481cf7f2e2dSJohn Marino Return the number of bytes actually transfered, or -1 if the
482cf7f2e2dSJohn Marino transfer is not supported or otherwise fails. Return of a non-negative
483cf7f2e2dSJohn Marino value less than LEN indicates that no further transfer is possible.
484cf7f2e2dSJohn Marino NOTE: This is different than the to_xfer_partial interface, in which
485cf7f2e2dSJohn Marino positive values less than LEN mean further transfers may be possible. */
4865796c8dcSSimon Schubert
4875796c8dcSSimon Schubert int
dcache_xfer_memory(struct target_ops * ops,DCACHE * dcache,CORE_ADDR memaddr,gdb_byte * myaddr,int len,int should_write)4885796c8dcSSimon Schubert dcache_xfer_memory (struct target_ops *ops, DCACHE *dcache,
4895796c8dcSSimon Schubert CORE_ADDR memaddr, gdb_byte *myaddr,
4905796c8dcSSimon Schubert int len, int should_write)
4915796c8dcSSimon Schubert {
4925796c8dcSSimon Schubert int i;
4935796c8dcSSimon Schubert int res;
4945796c8dcSSimon Schubert int (*xfunc) (DCACHE *dcache, CORE_ADDR addr, gdb_byte *ptr);
495cf7f2e2dSJohn Marino
4965796c8dcSSimon Schubert xfunc = should_write ? dcache_poke_byte : dcache_peek_byte;
4975796c8dcSSimon Schubert
4985796c8dcSSimon Schubert /* If this is a different inferior from what we've recorded,
4995796c8dcSSimon Schubert flush the cache. */
5005796c8dcSSimon Schubert
5015796c8dcSSimon Schubert if (! ptid_equal (inferior_ptid, dcache->ptid))
5025796c8dcSSimon Schubert {
5035796c8dcSSimon Schubert dcache_invalidate (dcache);
5045796c8dcSSimon Schubert dcache->ptid = inferior_ptid;
5055796c8dcSSimon Schubert }
5065796c8dcSSimon Schubert
5075796c8dcSSimon Schubert /* Do write-through first, so that if it fails, we don't write to
5085796c8dcSSimon Schubert the cache at all. */
5095796c8dcSSimon Schubert
5105796c8dcSSimon Schubert if (should_write)
5115796c8dcSSimon Schubert {
5125796c8dcSSimon Schubert res = target_write (ops, TARGET_OBJECT_RAW_MEMORY,
5135796c8dcSSimon Schubert NULL, myaddr, memaddr, len);
5145796c8dcSSimon Schubert if (res <= 0)
5155796c8dcSSimon Schubert return res;
5165796c8dcSSimon Schubert /* Update LEN to what was actually written. */
5175796c8dcSSimon Schubert len = res;
5185796c8dcSSimon Schubert }
5195796c8dcSSimon Schubert
5205796c8dcSSimon Schubert for (i = 0; i < len; i++)
5215796c8dcSSimon Schubert {
5225796c8dcSSimon Schubert if (!xfunc (dcache, memaddr + i, myaddr + i))
5235796c8dcSSimon Schubert {
5245796c8dcSSimon Schubert /* That failed. Discard its cache line so we don't have a
5255796c8dcSSimon Schubert partially read line. */
5265796c8dcSSimon Schubert dcache_invalidate_line (dcache, memaddr + i);
5275796c8dcSSimon Schubert /* If we're writing, we still wrote LEN bytes. */
5285796c8dcSSimon Schubert if (should_write)
5295796c8dcSSimon Schubert return len;
5305796c8dcSSimon Schubert else
5315796c8dcSSimon Schubert return i;
5325796c8dcSSimon Schubert }
5335796c8dcSSimon Schubert }
5345796c8dcSSimon Schubert
5355796c8dcSSimon Schubert return len;
5365796c8dcSSimon Schubert }
5375796c8dcSSimon Schubert
5385796c8dcSSimon Schubert /* FIXME: There would be some benefit to making the cache write-back and
5395796c8dcSSimon Schubert moving the writeback operation to a higher layer, as it could occur
5405796c8dcSSimon Schubert after a sequence of smaller writes have been completed (as when a stack
5415796c8dcSSimon Schubert frame is constructed for an inferior function call). Note that only
5425796c8dcSSimon Schubert moving it up one level to target_xfer_memory[_partial]() is not
5435796c8dcSSimon Schubert sufficient since we want to coalesce memory transfers that are
5445796c8dcSSimon Schubert "logically" connected but not actually a single call to one of the
5455796c8dcSSimon Schubert memory transfer functions. */
5465796c8dcSSimon Schubert
5475796c8dcSSimon Schubert /* Just update any cache lines which are already present. This is called
5485796c8dcSSimon Schubert by memory_xfer_partial in cases where the access would otherwise not go
5495796c8dcSSimon Schubert through the cache. */
5505796c8dcSSimon Schubert
5515796c8dcSSimon Schubert void
dcache_update(DCACHE * dcache,CORE_ADDR memaddr,gdb_byte * myaddr,int len)5525796c8dcSSimon Schubert dcache_update (DCACHE *dcache, CORE_ADDR memaddr, gdb_byte *myaddr, int len)
5535796c8dcSSimon Schubert {
5545796c8dcSSimon Schubert int i;
555cf7f2e2dSJohn Marino
5565796c8dcSSimon Schubert for (i = 0; i < len; i++)
5575796c8dcSSimon Schubert dcache_poke_byte (dcache, memaddr + i, myaddr + i);
5585796c8dcSSimon Schubert }
5595796c8dcSSimon Schubert
5605796c8dcSSimon Schubert static void
dcache_print_line(int index)5615796c8dcSSimon Schubert dcache_print_line (int index)
5625796c8dcSSimon Schubert {
5635796c8dcSSimon Schubert splay_tree_node n;
5645796c8dcSSimon Schubert struct dcache_block *db;
5655796c8dcSSimon Schubert int i, j;
5665796c8dcSSimon Schubert
5675796c8dcSSimon Schubert if (!last_cache)
5685796c8dcSSimon Schubert {
5695796c8dcSSimon Schubert printf_filtered (_("No data cache available.\n"));
5705796c8dcSSimon Schubert return;
5715796c8dcSSimon Schubert }
5725796c8dcSSimon Schubert
5735796c8dcSSimon Schubert n = splay_tree_min (last_cache->tree);
5745796c8dcSSimon Schubert
5755796c8dcSSimon Schubert for (i = index; i > 0; --i)
5765796c8dcSSimon Schubert {
5775796c8dcSSimon Schubert if (!n)
5785796c8dcSSimon Schubert break;
5795796c8dcSSimon Schubert n = splay_tree_successor (last_cache->tree, n->key);
5805796c8dcSSimon Schubert }
5815796c8dcSSimon Schubert
5825796c8dcSSimon Schubert if (!n)
5835796c8dcSSimon Schubert {
5845796c8dcSSimon Schubert printf_filtered (_("No such cache line exists.\n"));
5855796c8dcSSimon Schubert return;
5865796c8dcSSimon Schubert }
5875796c8dcSSimon Schubert
5885796c8dcSSimon Schubert db = (struct dcache_block *) n->value;
5895796c8dcSSimon Schubert
5905796c8dcSSimon Schubert printf_filtered (_("Line %d: address %s [%d hits]\n"),
591*ef5ccd6cSJohn Marino index, paddress (target_gdbarch (), db->addr), db->refs);
5925796c8dcSSimon Schubert
593a45ae5f8SJohn Marino for (j = 0; j < last_cache->line_size; j++)
5945796c8dcSSimon Schubert {
5955796c8dcSSimon Schubert printf_filtered ("%02x ", db->data[j]);
5965796c8dcSSimon Schubert
597c50c785cSJohn Marino /* Print a newline every 16 bytes (48 characters). */
598a45ae5f8SJohn Marino if ((j % 16 == 15) && (j != last_cache->line_size - 1))
5995796c8dcSSimon Schubert printf_filtered ("\n");
6005796c8dcSSimon Schubert }
6015796c8dcSSimon Schubert printf_filtered ("\n");
6025796c8dcSSimon Schubert }
6035796c8dcSSimon Schubert
6045796c8dcSSimon Schubert static void
dcache_info(char * exp,int tty)6055796c8dcSSimon Schubert dcache_info (char *exp, int tty)
6065796c8dcSSimon Schubert {
6075796c8dcSSimon Schubert splay_tree_node n;
608cf7f2e2dSJohn Marino int i, refcount;
6095796c8dcSSimon Schubert
6105796c8dcSSimon Schubert if (exp)
6115796c8dcSSimon Schubert {
6125796c8dcSSimon Schubert char *linestart;
613cf7f2e2dSJohn Marino
6145796c8dcSSimon Schubert i = strtol (exp, &linestart, 10);
6155796c8dcSSimon Schubert if (linestart == exp || i < 0)
6165796c8dcSSimon Schubert {
6175796c8dcSSimon Schubert printf_filtered (_("Usage: info dcache [linenumber]\n"));
6185796c8dcSSimon Schubert return;
6195796c8dcSSimon Schubert }
6205796c8dcSSimon Schubert
6215796c8dcSSimon Schubert dcache_print_line (i);
6225796c8dcSSimon Schubert return;
6235796c8dcSSimon Schubert }
6245796c8dcSSimon Schubert
625a45ae5f8SJohn Marino printf_filtered (_("Dcache %u lines of %u bytes each.\n"),
626a45ae5f8SJohn Marino dcache_size,
627a45ae5f8SJohn Marino last_cache ? (unsigned) last_cache->line_size
628a45ae5f8SJohn Marino : dcache_line_size);
6295796c8dcSSimon Schubert
6305796c8dcSSimon Schubert if (!last_cache || ptid_equal (last_cache->ptid, null_ptid))
6315796c8dcSSimon Schubert {
6325796c8dcSSimon Schubert printf_filtered (_("No data cache available.\n"));
6335796c8dcSSimon Schubert return;
6345796c8dcSSimon Schubert }
6355796c8dcSSimon Schubert
6365796c8dcSSimon Schubert printf_filtered (_("Contains data for %s\n"),
6375796c8dcSSimon Schubert target_pid_to_str (last_cache->ptid));
6385796c8dcSSimon Schubert
6395796c8dcSSimon Schubert refcount = 0;
6405796c8dcSSimon Schubert
6415796c8dcSSimon Schubert n = splay_tree_min (last_cache->tree);
6425796c8dcSSimon Schubert i = 0;
6435796c8dcSSimon Schubert
6445796c8dcSSimon Schubert while (n)
6455796c8dcSSimon Schubert {
6465796c8dcSSimon Schubert struct dcache_block *db = (struct dcache_block *) n->value;
6475796c8dcSSimon Schubert
6485796c8dcSSimon Schubert printf_filtered (_("Line %d: address %s [%d hits]\n"),
649*ef5ccd6cSJohn Marino i, paddress (target_gdbarch (), db->addr), db->refs);
6505796c8dcSSimon Schubert i++;
6515796c8dcSSimon Schubert refcount += db->refs;
6525796c8dcSSimon Schubert
6535796c8dcSSimon Schubert n = splay_tree_successor (last_cache->tree, n->key);
6545796c8dcSSimon Schubert }
6555796c8dcSSimon Schubert
6565796c8dcSSimon Schubert printf_filtered (_("Cache state: %d active lines, %d hits\n"), i, refcount);
6575796c8dcSSimon Schubert }
6585796c8dcSSimon Schubert
659a45ae5f8SJohn Marino static void
set_dcache_size(char * args,int from_tty,struct cmd_list_element * c)660a45ae5f8SJohn Marino set_dcache_size (char *args, int from_tty,
661a45ae5f8SJohn Marino struct cmd_list_element *c)
662a45ae5f8SJohn Marino {
663a45ae5f8SJohn Marino if (dcache_size == 0)
664a45ae5f8SJohn Marino {
665a45ae5f8SJohn Marino dcache_size = DCACHE_DEFAULT_SIZE;
666a45ae5f8SJohn Marino error (_("Dcache size must be greater than 0."));
667a45ae5f8SJohn Marino }
668a45ae5f8SJohn Marino if (last_cache)
669a45ae5f8SJohn Marino dcache_invalidate (last_cache);
670a45ae5f8SJohn Marino }
671a45ae5f8SJohn Marino
672a45ae5f8SJohn Marino static void
set_dcache_line_size(char * args,int from_tty,struct cmd_list_element * c)673a45ae5f8SJohn Marino set_dcache_line_size (char *args, int from_tty,
674a45ae5f8SJohn Marino struct cmd_list_element *c)
675a45ae5f8SJohn Marino {
676a45ae5f8SJohn Marino if (dcache_line_size < 2
677a45ae5f8SJohn Marino || (dcache_line_size & (dcache_line_size - 1)) != 0)
678a45ae5f8SJohn Marino {
679a45ae5f8SJohn Marino unsigned d = dcache_line_size;
680a45ae5f8SJohn Marino dcache_line_size = DCACHE_DEFAULT_LINE_SIZE;
681a45ae5f8SJohn Marino error (_("Invalid dcache line size: %u (must be power of 2)."), d);
682a45ae5f8SJohn Marino }
683a45ae5f8SJohn Marino if (last_cache)
684a45ae5f8SJohn Marino dcache_invalidate (last_cache);
685a45ae5f8SJohn Marino }
686a45ae5f8SJohn Marino
687a45ae5f8SJohn Marino static void
set_dcache_command(char * arg,int from_tty)688a45ae5f8SJohn Marino set_dcache_command (char *arg, int from_tty)
689a45ae5f8SJohn Marino {
690a45ae5f8SJohn Marino printf_unfiltered (
691a45ae5f8SJohn Marino "\"set dcache\" must be followed by the name of a subcommand.\n");
692a45ae5f8SJohn Marino help_list (dcache_set_list, "set dcache ", -1, gdb_stdout);
693a45ae5f8SJohn Marino }
694a45ae5f8SJohn Marino
695a45ae5f8SJohn Marino static void
show_dcache_command(char * args,int from_tty)696a45ae5f8SJohn Marino show_dcache_command (char *args, int from_tty)
697a45ae5f8SJohn Marino {
698a45ae5f8SJohn Marino cmd_show_list (dcache_show_list, from_tty, "");
699a45ae5f8SJohn Marino }
700a45ae5f8SJohn Marino
7015796c8dcSSimon Schubert void
_initialize_dcache(void)7025796c8dcSSimon Schubert _initialize_dcache (void)
7035796c8dcSSimon Schubert {
7045796c8dcSSimon Schubert add_setshow_boolean_cmd ("remotecache", class_support,
7055796c8dcSSimon Schubert &dcache_enabled_p, _("\
7065796c8dcSSimon Schubert Set cache use for remote targets."), _("\
7075796c8dcSSimon Schubert Show cache use for remote targets."), _("\
7085796c8dcSSimon Schubert This used to enable the data cache for remote targets. The cache\n\
7095796c8dcSSimon Schubert functionality is now controlled by the memory region system and the\n\
7105796c8dcSSimon Schubert \"stack-cache\" flag; \"remotecache\" now does nothing and\n\
7115796c8dcSSimon Schubert exists only for compatibility reasons."),
7125796c8dcSSimon Schubert NULL,
7135796c8dcSSimon Schubert show_dcache_enabled_p,
7145796c8dcSSimon Schubert &setlist, &showlist);
7155796c8dcSSimon Schubert
7165796c8dcSSimon Schubert add_info ("dcache", dcache_info,
7175796c8dcSSimon Schubert _("\
7185796c8dcSSimon Schubert Print information on the dcache performance.\n\
7195796c8dcSSimon Schubert With no arguments, this command prints the cache configuration and a\n\
7205796c8dcSSimon Schubert summary of each line in the cache. Use \"info dcache <lineno> to dump\"\n\
7215796c8dcSSimon Schubert the contents of a given line."));
722a45ae5f8SJohn Marino
723a45ae5f8SJohn Marino add_prefix_cmd ("dcache", class_obscure, set_dcache_command, _("\
724a45ae5f8SJohn Marino Use this command to set number of lines in dcache and line-size."),
725a45ae5f8SJohn Marino &dcache_set_list, "set dcache ", /*allow_unknown*/0, &setlist);
726a45ae5f8SJohn Marino add_prefix_cmd ("dcache", class_obscure, show_dcache_command, _("\
727a45ae5f8SJohn Marino Show dcachesettings."),
728a45ae5f8SJohn Marino &dcache_show_list, "show dcache ", /*allow_unknown*/0, &showlist);
729a45ae5f8SJohn Marino
730a45ae5f8SJohn Marino add_setshow_uinteger_cmd ("line-size", class_obscure,
731a45ae5f8SJohn Marino &dcache_line_size, _("\
732a45ae5f8SJohn Marino Set dcache line size in bytes (must be power of 2)."), _("\
733a45ae5f8SJohn Marino Show dcache line size."),
734a45ae5f8SJohn Marino NULL,
735a45ae5f8SJohn Marino set_dcache_line_size,
736a45ae5f8SJohn Marino NULL,
737a45ae5f8SJohn Marino &dcache_set_list, &dcache_show_list);
738a45ae5f8SJohn Marino add_setshow_uinteger_cmd ("size", class_obscure,
739a45ae5f8SJohn Marino &dcache_size, _("\
740a45ae5f8SJohn Marino Set number of dcache lines."), _("\
741a45ae5f8SJohn Marino Show number of dcache lines."),
742a45ae5f8SJohn Marino NULL,
743a45ae5f8SJohn Marino set_dcache_size,
744a45ae5f8SJohn Marino NULL,
745a45ae5f8SJohn Marino &dcache_set_list, &dcache_show_list);
7465796c8dcSSimon Schubert }
747