]>
Commit | Line | Data |
---|---|---|
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 | ||
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., 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 |
26 | int 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. */ | |
43 | void | |
44 | dcache_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 | 63 | static |
755892d6 RP |
64 | struct dcache_block * |
65 | dcache_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 | 88 | static |
755892d6 RP |
89 | int |
90 | dcache_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 | 107 | static |
755892d6 RP |
108 | struct dcache_block * |
109 | dcache_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 |
133 | int |
134 | dcache_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. */ | |
163 | void | |
164 | dcache_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. */ | |
200 | DCACHE * | |
201 | dcache_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 |
223 | void |
224 | _initialitize_dcache () | |
225 | { | |
226 | add_show_from_set | |
227 | (add_set_cmd ("remotecache", class_support, var_boolean, | |
228 | (char *) &remote_dcache, | |
229 | "\ | |
230 | Set cache use for remote targets.\n\ | |
231 | When on, use data caching for remote targets. For many remote targets\n\ | |
232 | this option can offer better throughput for reading target memory.\n\ | |
233 | Unfortunately, gdb does not currently know anything about volatile\n\ | |
234 | registers and thus data caching will produce incorrect results with\n\ | |
235 | volatile registers are in use. By default, this option is off.", | |
236 | &setlist), | |
237 | &showlist); | |
238 | } |