OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [gdb/] [dcache.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.