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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [gdb-5.0/] [gdb/] [dcache.c] - Blame information for rev 1774

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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