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