diff options
author | Stan Shebs <shebs@codesourcery.com> | 1999-04-16 01:34:07 +0000 |
---|---|---|
committer | Stan Shebs <shebs@codesourcery.com> | 1999-04-16 01:34:07 +0000 |
commit | 071ea11e85eb9d529cc5eb3d35f6247466a21b99 (patch) | |
tree | 5deda65b8d7b04d1f4cbc534c3206d328e1267ec /gdb/dcache.c | |
parent | 1730ec6b1848f0f32154277f788fb29f88d8475b (diff) | |
download | gdb-071ea11e85eb9d529cc5eb3d35f6247466a21b99.zip gdb-071ea11e85eb9d529cc5eb3d35f6247466a21b99.tar.gz gdb-071ea11e85eb9d529cc5eb3d35f6247466a21b99.tar.bz2 |
Initial creation of sourceware repository
Diffstat (limited to 'gdb/dcache.c')
-rw-r--r-- | gdb/dcache.c | 558 |
1 files changed, 0 insertions, 558 deletions
diff --git a/gdb/dcache.c b/gdb/dcache.c deleted file mode 100644 index a97a940..0000000 --- a/gdb/dcache.c +++ /dev/null @@ -1,558 +0,0 @@ -/* Caching code. Typically used by remote back ends for - caching remote memory. - - Copyright 1992, 1993, 1995, 1998 Free Software Foundation, Inc. - - This file is part of GDB. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#include "defs.h" -#include "dcache.h" -#include "gdbcmd.h" -#include "gdb_string.h" -#include "gdbcore.h" - -/* - The data cache could lead to incorrect results because it doesn't know - about volatile variables, thus making it impossible to debug - functions which use memory mapped I/O devices. - - set remotecache 0 - - In those cases. - - In general the dcache speeds up performance, some speed improvement - comes from the actual caching mechanism, but the major gain is in - the reduction of the remote protocol overhead; instead of reading - or writing a large area of memory in 4 byte requests, the cache - bundles up the requests into 32 byte (actually LINE_SIZE) chunks. - Reducing the overhead to an eighth of what it was. This is very - obvious when displaying a large amount of data, - - eg, x/200x 0 - - caching | no yes - ---------------------------- - first time | 4 sec 2 sec improvement due to chunking - second time | 4 sec 0 sec improvement due to caching - - The cache structure is unusual, we keep a number of cache blocks - (DCACHE_SIZE) and each one caches a LINE_SIZEed area of memory. - Within each line we remember the address of the line (always a - multiple of the LINE_SIZE) and a vector of bytes over the range. - There's another vector which contains the state of the bytes. - - ENTRY_BAD means that the byte is just plain wrong, and has no - correspondence with anything else (as it would when the cache is - turned on, but nothing has been done to it. - - ENTRY_DIRTY means that the byte has some data in it which should be - written out to the remote target one day, but contains correct - data. ENTRY_OK means that the data is the same in the cache as it - is in remote memory. - - - The ENTRY_DIRTY state is necessary because GDB likes to write large - lumps of memory in small bits. If the caching mechanism didn't - maintain the DIRTY information, then something like a two byte - write would mean that the entire cache line would have to be read, - the two bytes modified and then written out again. The alternative - would be to not read in the cache line in the first place, and just - write the two bytes directly into target memory. The trouble with - that is that it really nails performance, because of the remote - protocol overhead. This way, all those little writes are bundled - up into an entire cache line write in one go, without having to - read the cache line in the first place. - - - */ - - -/* This value regulates the number of cache blocks stored. - Smaller values reduce the time spent searching for a cache - line, and reduce memory requirements, but increase the risk - of a line not being in memory */ - -#define DCACHE_SIZE 64 - -/* This value regulates the size of a cache line. Smaller values - reduce the time taken to read a single byte, but reduce overall - throughput. */ - -#define LINE_SIZE_POWER (5) -#define LINE_SIZE (1 << LINE_SIZE_POWER) - -/* Each cache block holds LINE_SIZE bytes of data - starting at a multiple-of-LINE_SIZE address. */ - -#define LINE_SIZE_MASK ((LINE_SIZE - 1)) -#define XFORM(x) ((x) & LINE_SIZE_MASK) -#define MASK(x) ((x) & ~LINE_SIZE_MASK) - - -#define ENTRY_BAD 0 /* data at this byte is wrong */ -#define ENTRY_DIRTY 1 /* data at this byte needs to be written back */ -#define ENTRY_OK 2 /* data at this byte is same as in memory */ - - -struct dcache_block -{ - struct dcache_block *p; /* next in list */ - CORE_ADDR addr; /* Address for which data is recorded. */ - char data[LINE_SIZE]; /* bytes at given address */ - unsigned char state[LINE_SIZE]; /* what state the data is in */ - - /* whether anything in state is dirty - used to speed up the - dirty scan. */ - int anydirty; - - int refs; -}; - - -struct dcache_struct -{ - /* Function to actually read the target memory. */ - memxferfunc read_memory; - - /* Function to actually write the target memory */ - memxferfunc write_memory; - - /* free list */ - struct dcache_block *free_head; - struct dcache_block *free_tail; - - /* in use list */ - struct dcache_block *valid_head; - struct dcache_block *valid_tail; - - /* The cache itself. */ - struct dcache_block *the_cache; - - /* potentially, if the cache was enabled, and then turned off, and - then turned on again, the stuff in it could be stale, so this is - used to mark it */ - int cache_has_stuff; -} ; - -static int dcache_poke_byte PARAMS ((DCACHE *dcache, CORE_ADDR addr, - char *ptr)); - -static int dcache_peek_byte PARAMS ((DCACHE *dcache, CORE_ADDR addr, - char *ptr)); - -static struct dcache_block *dcache_hit PARAMS ((DCACHE *dcache, - CORE_ADDR addr)); - -static int dcache_write_line PARAMS ((DCACHE *dcache,struct dcache_block *db)); - -static struct dcache_block *dcache_alloc PARAMS ((DCACHE *dcache)); - -static int dcache_writeback PARAMS ((DCACHE *dcache)); - -static void dcache_info PARAMS ((char *exp, int tty)); - -void _initialize_dcache PARAMS ((void)); - -int remote_dcache = 0; - -DCACHE *last_cache; /* Used by info dcache */ - - -/* Free all the data cache blocks, thus discarding all cached data. */ - -void -dcache_flush (dcache) - DCACHE *dcache; -{ - int i; - dcache->valid_head = 0; - dcache->valid_tail = 0; - - dcache->free_head = 0; - dcache->free_tail = 0; - - for (i = 0; i < DCACHE_SIZE; i++) - { - struct dcache_block *db = dcache->the_cache + i; - - if (!dcache->free_head) - dcache->free_head = db; - else - dcache->free_tail->p = db; - dcache->free_tail = db; - db->p = 0; - } - - dcache->cache_has_stuff = 0; - - return; -} - -/* If addr is present in the dcache, return the address of the block - containing it. */ - -static struct dcache_block * -dcache_hit (dcache, addr) - DCACHE *dcache; - CORE_ADDR addr; -{ - register struct dcache_block *db; - - /* Search all cache blocks for one that is at this address. */ - db = dcache->valid_head; - - while (db) - { - if (MASK(addr) == db->addr) - { - db->refs++; - return db; - } - db = db->p; - } - - return NULL; -} - -/* Make sure that anything in this line which needs to - be written is. */ - -static int -dcache_write_line (dcache, db) - DCACHE *dcache; - register struct dcache_block *db; -{ - int s; - int e; - s = 0; - if (db->anydirty) - { - for (s = 0; s < LINE_SIZE; s++) - { - if (db->state[s] == ENTRY_DIRTY) - { - int len = 0; - for (e = s ; e < LINE_SIZE; e++, len++) - if (db->state[e] != ENTRY_DIRTY) - break; - { - /* all bytes from s..s+len-1 need to - be written out */ - int done = 0; - while (done < len) { - int t = dcache->write_memory (db->addr + s + done, - db->data + s + done, - len - done); - if (t == 0) - return 0; - done += t; - } - memset (db->state + s, ENTRY_OK, len); - s = e; - } - } - } - db->anydirty = 0; - } - return 1; -} - - -/* Get a free cache block, put or keep it on the valid list, - and return its address. The caller should store into the block - the address and data that it describes, then remque it from the - free list and insert it into the valid list. This procedure - prevents errors from creeping in if a memory retrieval is - interrupted (which used to put garbage blocks in the valid - list...). */ - -static struct dcache_block * -dcache_alloc (dcache) - DCACHE *dcache; -{ - register struct dcache_block *db; - - if (remote_dcache == 0) - abort (); - - /* Take something from the free list */ - db = dcache->free_head; - if (db) - { - dcache->free_head = db->p; - } - else - { - /* Nothing left on free list, so grab one from the valid list */ - db = dcache->valid_head; - dcache->valid_head = db->p; - - dcache_write_line (dcache, db); - } - - /* append this line to end of valid list */ - if (!dcache->valid_head) - dcache->valid_head = db; - else - dcache->valid_tail->p = db; - dcache->valid_tail = db; - db->p = 0; - - return db; -} - -/* Using the data cache DCACHE return the contents of the byte at - address ADDR in the remote machine. - - Returns 0 on error. */ - -static int -dcache_peek_byte (dcache, addr, ptr) - DCACHE *dcache; - CORE_ADDR addr; - char *ptr; -{ - register struct dcache_block *db = dcache_hit (dcache, addr); - int ok=1; - int done = 0; - if (db == 0 - || db->state[XFORM (addr)] == ENTRY_BAD) - { - if (db) - { - dcache_write_line (dcache, db); - } - else - db = dcache_alloc (dcache); - immediate_quit++; - db->addr = MASK (addr); - while (done < LINE_SIZE) - { - int try = - (*dcache->read_memory) - (db->addr + done, - db->data + done, - LINE_SIZE - done); - if (try == 0) - return 0; - done += try; - } - immediate_quit--; - - memset (db->state, ENTRY_OK, sizeof (db->data)); - db->anydirty = 0; - } - *ptr = db->data[XFORM (addr)]; - return ok; -} - -/* Writeback any dirty lines to the remote. */ -static int -dcache_writeback (dcache) - DCACHE *dcache; -{ - struct dcache_block *db; - - db = dcache->valid_head; - - while (db) - { - if (!dcache_write_line (dcache, db)) - return 0; - db = db->p; - } - return 1; -} - - -/* Using the data cache DCACHE return the contents of the word at - address ADDR in the remote machine. */ -int -dcache_fetch (dcache, addr) - DCACHE *dcache; - CORE_ADDR addr; -{ - int res; - - if (dcache_xfer_memory (dcache, addr, (char *)&res, sizeof res, 0) != sizeof res) - memory_error (EIO, addr); - - return res; -} - - -/* Write the byte at PTR into ADDR in the data cache. - Return zero on write error. - */ - -static int -dcache_poke_byte (dcache, addr, ptr) - DCACHE *dcache; - CORE_ADDR addr; - char *ptr; -{ - register struct dcache_block *db = dcache_hit (dcache, addr); - - if (!db) - { - db = dcache_alloc (dcache); - db->addr = MASK (addr); - memset (db->state, ENTRY_BAD, sizeof (db->data)); - } - - db->data[XFORM (addr)] = *ptr; - db->state[XFORM (addr)] = ENTRY_DIRTY; - db->anydirty = 1; - return 1; -} - -/* Write the word at ADDR both in the data cache and in the remote machine. - Return zero on write error. - */ - -int -dcache_poke (dcache, addr, data) - DCACHE *dcache; - CORE_ADDR addr; - int data; -{ - if (dcache_xfer_memory (dcache, addr, (char *)&data, sizeof data, 1) != sizeof data) - return 0; - - return dcache_writeback (dcache); -} - - -/* Initialize the data cache. */ -DCACHE * -dcache_init (reading, writing) - memxferfunc reading; - memxferfunc writing; -{ - int csize = sizeof (struct dcache_block) * DCACHE_SIZE; - DCACHE *dcache; - - dcache = (DCACHE *) xmalloc (sizeof (*dcache)); - dcache->read_memory = reading; - dcache->write_memory = writing; - - dcache->the_cache = (struct dcache_block *) xmalloc (csize); - memset (dcache->the_cache, 0, csize); - - dcache_flush (dcache); - - last_cache = dcache; - return dcache; -} - -/* Read or write LEN bytes from inferior memory at MEMADDR, transferring - to or from debugger address MYADDR. Write to inferior if SHOULD_WRITE is - nonzero. - - Returns length of data written or read; 0 for error. - - This routine is indended to be called by remote_xfer_ functions. */ - -int -dcache_xfer_memory (dcache, memaddr, myaddr, len, should_write) - DCACHE *dcache; - CORE_ADDR memaddr; - char *myaddr; - int len; - int should_write; -{ - int i; - - if (remote_dcache) - { - int (*xfunc) PARAMS ((DCACHE *dcache, CORE_ADDR addr, char *ptr)); - xfunc = should_write ? dcache_poke_byte : dcache_peek_byte; - - for (i = 0; i < len; i++) - { - if (!xfunc (dcache, memaddr + i, myaddr + i)) - return 0; - } - dcache->cache_has_stuff = 1; - dcache_writeback (dcache); - } - else - { - memxferfunc xfunc; - xfunc = should_write ? dcache->write_memory : dcache->read_memory; - - if (dcache->cache_has_stuff) - dcache_flush (dcache); - - len = xfunc (memaddr, myaddr, len); - } - return len; -} - -static void -dcache_info (exp, tty) - char *exp; - int tty; -{ - struct dcache_block *p; - - if (!remote_dcache) - { - printf_filtered ("Dcache not enabled\n"); - return; - } - printf_filtered ("Dcache enabled, line width %d, depth %d\n", - LINE_SIZE, DCACHE_SIZE); - - printf_filtered ("Cache state:\n"); - - for (p = last_cache->valid_head; p; p = p->p) - { - int j; - printf_filtered ("Line at %08xd, referenced %d times\n", - p->addr, p->refs); - - for (j = 0; j < LINE_SIZE; j++) - printf_filtered ("%02x", p->data[j] & 0xFF); - printf_filtered ("\n"); - - for (j = 0; j < LINE_SIZE; j++) - printf_filtered (" %2x", p->state[j]); - printf_filtered ("\n"); - } -} - -void -_initialize_dcache () -{ - add_show_from_set - (add_set_cmd ("remotecache", class_support, var_boolean, - (char *) &remote_dcache, - "\ -Set cache use for remote targets.\n\ -When on, use data caching for remote targets. For many remote targets\n\ -this option can offer better throughput for reading target memory.\n\ -Unfortunately, gdb does not currently know anything about volatile\n\ -registers and thus data caching will produce incorrect results with\n\ -volatile registers are in use. By default, this option is on.", - &setlist), - &showlist); - - add_info ("dcache", dcache_info, - "Print information on the dcache performance."); - -} |