(PCINDEX): New macro.
[deliverable/binutils-gdb.git] / gdb / dcache.c
CommitLineData
755892d6
RP
1/* Caching code. Typically used by remote back ends for
2 caching remote memory.
3
4 Copyright 1992, 1993 Free Software Foundation, Inc.
5
6This file is part of GDB.
7
8This program is free software; you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation; either version 2 of the License, or
11(at your option) any later version.
12
13This program is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with this program; if not, write to the Free Software
20Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
21
22#include "defs.h"
23#include "dcache.h"
d538b510 24#include "gdbcmd.h"
755892d6 25
92c6bf4d
MM
26int remote_dcache = 0;
27
677653a0
MM
28/* In case the system header files define a prototype for insque and
29 remque that uses a pointer to a struct qelem, silence the warnings */
4e71f1ae
MM
30#define Insque(a,b) insque((PTR)(a), (PTR)(b))
31#define Remque(a) remque((PTR)(a))
677653a0 32
755892d6
RP
33/* The data cache records all the data read from the remote machine
34 since the last time it stopped.
35
9e58280a
RP
36 Each cache block holds LINE_SIZE bytes of data
37 starting at a multiple-of-LINE_SIZE address. */
755892d6
RP
38
39#define LINE_SIZE_MASK ((LINE_SIZE - 1)) /* eg 7*2+1= 111*/
40#define XFORM(x) (((x) & LINE_SIZE_MASK) >> 2)
41
42/* Free all the data cache blocks, thus discarding all cached data. */
43void
44dcache_flush (dcache)
45 DCACHE *dcache;
46{
47 register struct dcache_block *db;
48
d538b510
RP
49 if (remote_dcache > 0)
50 while ((db = dcache->dcache_valid.next) != &dcache->dcache_valid)
51 {
92c6bf4d
MM
52 Remque (db);
53 Insque (db, &dcache->dcache_free);
d538b510
RP
54 }
55
56 return;
755892d6
RP
57}
58
59/*
60 * If addr is present in the dcache, return the address of the block
61 * containing it.
62 */
d538b510 63static
755892d6
RP
64struct dcache_block *
65dcache_hit (dcache, addr)
66 DCACHE *dcache;
67 unsigned int addr;
68{
69 register struct dcache_block *db;
70
d538b510
RP
71 if (addr & 3
72 || remote_dcache == 0)
755892d6
RP
73 abort ();
74
75 /* Search all cache blocks for one that is at this address. */
76 db = dcache->dcache_valid.next;
77 while (db != &dcache->dcache_valid)
78 {
79 if ((addr & ~LINE_SIZE_MASK) == db->addr)
80 return db;
81 db = db->next;
82 }
d538b510 83
755892d6
RP
84 return NULL;
85}
86
87/* Return the int data at address ADDR in dcache block DC. */
d538b510 88static
755892d6
RP
89int
90dcache_value (db, addr)
91 struct dcache_block *db;
92 unsigned int addr;
93{
d538b510
RP
94 if (addr & 3
95 || remote_dcache == 0)
755892d6
RP
96 abort ();
97 return (db->data[XFORM (addr)]);
98}
99
100/* Get a free cache block, put or keep it on the valid list,
101 and return its address. The caller should store into the block
102 the address and data that it describes, then remque it from the
103 free list and insert it into the valid list. This procedure
9e58280a
RP
104 prevents errors from creeping in if a memory retrieval is
105 interrupted (which used to put garbage blocks in the valid
106 list...). */
d538b510 107static
755892d6
RP
108struct dcache_block *
109dcache_alloc (dcache)
110 DCACHE *dcache;
111{
112 register struct dcache_block *db;
113
d538b510
RP
114 if (remote_dcache == 0)
115 abort();
116
755892d6
RP
117 if ((db = dcache->dcache_free.next) == &dcache->dcache_free)
118 {
119 /* If we can't get one from the free list, take last valid and put
120 it on the free list. */
121 db = dcache->dcache_valid.last;
92c6bf4d
MM
122 Remque (db);
123 Insque (db, &dcache->dcache_free);
755892d6
RP
124 }
125
92c6bf4d
MM
126 Remque (db);
127 Insque (db, &dcache->dcache_valid);
755892d6
RP
128 return (db);
129}
130
d538b510
RP
131/* Using the data cache DCACHE return the contents of the word at
132 address ADDR in the remote machine. */
755892d6
RP
133int
134dcache_fetch (dcache, addr)
135 DCACHE *dcache;
136 CORE_ADDR addr;
137{
138 register struct dcache_block *db;
139
d538b510
RP
140 if (remote_dcache == 0)
141 {
142 int i;
143
144 (*dcache->read_memory) (addr, (unsigned char *) &i, 4);
145 return(i);
146 }
147
755892d6
RP
148 db = dcache_hit (dcache, addr);
149 if (db == 0)
150 {
151 db = dcache_alloc (dcache);
152 immediate_quit++;
153 (*dcache->read_memory) (addr & ~LINE_SIZE_MASK, (unsigned char *) db->data, LINE_SIZE);
154 immediate_quit--;
155 db->addr = addr & ~LINE_SIZE_MASK;
92c6bf4d
MM
156 Remque (db); /* Off the free list */
157 Insque (db, &dcache->dcache_valid); /* On the valid list */
755892d6
RP
158 }
159 return (dcache_value (db, addr));
160}
161
162/* Write the word at ADDR both in the data cache and in the remote machine. */
163void
164dcache_poke (dcache, addr, data)
165 DCACHE *dcache;
166 CORE_ADDR addr;
167 int data;
168{
169 register struct dcache_block *db;
170
d538b510
RP
171 if (remote_dcache == 0)
172 {
173 (*dcache->write_memory) (addr, (unsigned char *) &data, 4);
174 return;
175 }
176
755892d6
RP
177 /* First make sure the word is IN the cache. DB is its cache block. */
178 db = dcache_hit (dcache, addr);
179 if (db == 0)
180 {
181 db = dcache_alloc (dcache);
182 immediate_quit++;
183 (*dcache->write_memory) (addr & ~LINE_SIZE_MASK, (unsigned char *) db->data, LINE_SIZE);
184 immediate_quit--;
185 db->addr = addr & ~LINE_SIZE_MASK;
92c6bf4d
MM
186 Remque (db); /* Off the free list */
187 Insque (db, &dcache->dcache_valid); /* On the valid list */
755892d6
RP
188 }
189
190 /* Modify the word in the cache. */
191 db->data[XFORM (addr)] = data;
192
193 /* Send the changed word. */
194 immediate_quit++;
195 (*dcache->write_memory) (addr, (unsigned char *) &data, 4);
196 immediate_quit--;
197}
198
199/* Initialize the data cache. */
200DCACHE *
201dcache_init (reading, writing)
202 memxferfunc reading;
203 memxferfunc writing;
204{
205 register i;
206 register struct dcache_block *db;
207 DCACHE *dcache;
208
ac7a377f 209 dcache = (DCACHE *) xmalloc (sizeof (*dcache));
755892d6
RP
210 dcache->read_memory = reading;
211 dcache->write_memory = writing;
ac7a377f
JK
212 dcache->the_cache = (struct dcache_block *)
213 xmalloc (sizeof (*dcache->the_cache) * DCACHE_SIZE);
755892d6
RP
214
215 dcache->dcache_free.next = dcache->dcache_free.last = &dcache->dcache_free;
216 dcache->dcache_valid.next = dcache->dcache_valid.last = &dcache->dcache_valid;
217 for (db = dcache->the_cache, i = 0; i < DCACHE_SIZE; i++, db++)
92c6bf4d 218 Insque (db, &dcache->dcache_free);
755892d6
RP
219
220 return(dcache);
221}
222
d538b510
RP
223void
224_initialitize_dcache ()
225{
226 add_show_from_set
227 (add_set_cmd ("remotecache", class_support, var_boolean,
228 (char *) &remote_dcache,
229 "\
230Set cache use for remote targets.\n\
231When on, use data caching for remote targets. For many remote targets\n\
232this option can offer better throughput for reading target memory.\n\
233Unfortunately, gdb does not currently know anything about volatile\n\
234registers and thus data caching will produce incorrect results with\n\
235volatile registers are in use. By default, this option is off.",
236 &setlist),
237 &showlist);
238}
This page took 0.102518 seconds and 4 git commands to generate.