Automatic Copyright Year update after running gdb/copyright.py
[deliverable/binutils-gdb.git] / sim / common / sim-arange.c
CommitLineData
c906108c 1/* Address ranges.
88b9d363 2 Copyright (C) 1998-2022 Free Software Foundation, Inc.
c906108c
SS
3 Contributed by Cygnus Solutions.
4
5This file is part of the GNU Simulators.
6
7This program is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
4744ac1b
JB
9the Free Software Foundation; either version 3 of the License, or
10(at your option) any later version.
c906108c
SS
11
12This program is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
4744ac1b
JB
17You should have received a copy of the GNU General Public License
18along with this program. If not, see <http://www.gnu.org/licenses/>. */
c906108c 19
ef986697
SH
20#ifndef _SIM_ARANGE_C_
21#define _SIM_ARANGE_C_
c906108c 22
6df01ab8
MF
23/* This must come before any other includes. */
24#include "defs.h"
25
c906108c
SS
26#include "libiberty.h"
27#include "sim-basics.h"
ef986697 28#include "sim-arange.h"
c906108c 29
c906108c 30#include <stdlib.h>
c4093a6a 31#include <string.h>
c4093a6a 32
c906108c
SS
33/* Insert a range. */
34
35static void
36insert_range (ADDR_SUBRANGE **pos, ADDR_SUBRANGE *asr)
37{
38 asr->next = *pos;
39 *pos = asr;
40}
41
42/* Delete a range. */
43
44static void
45delete_range (ADDR_SUBRANGE **thisasrp)
46{
47 ADDR_SUBRANGE *thisasr;
48
49 thisasr = *thisasrp;
50 *thisasrp = thisasr->next;
51
52 free (thisasr);
53}
54
55/* Add or delete an address range.
56 This code was borrowed from linux's locks.c:posix_lock_file().
57 ??? Todo: Given our simpler needs this could be simplified
58 (split into two fns). */
59
60static void
61frob_range (ADDR_RANGE *ar, address_word start, address_word end, int delete_p)
62{
63 ADDR_SUBRANGE *asr;
64 ADDR_SUBRANGE *new_asr, *new_asr2;
65 ADDR_SUBRANGE *left = NULL;
66 ADDR_SUBRANGE *right = NULL;
67 ADDR_SUBRANGE **before;
68 ADDR_SUBRANGE init_caller;
69 ADDR_SUBRANGE *caller = &init_caller;
70 int added_p = 0;
71
72 memset (caller, 0, sizeof (ADDR_SUBRANGE));
73 new_asr = ZALLOC (ADDR_SUBRANGE);
74 new_asr2 = ZALLOC (ADDR_SUBRANGE);
75
76 caller->start = start;
77 caller->end = end;
78 before = &ar->ranges;
79
80 while ((asr = *before) != NULL)
81 {
82 if (! delete_p)
83 {
84 /* Try next range if current range preceeds new one and not
85 adjacent or overlapping. */
86 if (asr->end < caller->start - 1)
87 goto next_range;
88
89 /* Break out if new range preceeds current one and not
90 adjacent or overlapping. */
91 if (asr->start > caller->end + 1)
92 break;
93
94 /* If we come here, the new and current ranges are adjacent or
95 overlapping. Make one range yielding from the lower start address
96 of both ranges to the higher end address. */
97 if (asr->start > caller->start)
98 asr->start = caller->start;
99 else
100 caller->start = asr->start;
101 if (asr->end < caller->end)
102 asr->end = caller->end;
103 else
104 caller->end = asr->end;
105
106 if (added_p)
107 {
108 delete_range (before);
109 continue;
110 }
111 caller = asr;
112 added_p = 1;
113 }
114 else /* deleting a range */
115 {
116 /* Try next range if current range preceeds new one. */
117 if (asr->end < caller->start)
118 goto next_range;
119
120 /* Break out if new range preceeds current one. */
121 if (asr->start > caller->end)
122 break;
123
124 added_p = 1;
125
126 if (asr->start < caller->start)
127 left = asr;
128
129 /* If the next range in the list has a higher end
130 address than the new one, insert the new one here. */
131 if (asr->end > caller->end)
132 {
133 right = asr;
134 break;
135 }
136 if (asr->start >= caller->start)
137 {
138 /* The new range completely replaces an old
139 one (This may happen several times). */
140 if (added_p)
141 {
142 delete_range (before);
143 continue;
144 }
145
146 /* Replace the old range with the new one. */
147 asr->start = caller->start;
148 asr->end = caller->end;
149 caller = asr;
150 added_p = 1;
151 }
152 }
153
154 /* Go on to next range. */
155 next_range:
156 before = &asr->next;
157 }
158
159 if (!added_p)
160 {
161 if (delete_p)
162 goto out;
163 new_asr->start = caller->start;
164 new_asr->end = caller->end;
165 insert_range (before, new_asr);
166 new_asr = NULL;
167 }
168 if (right)
169 {
170 if (left == right)
171 {
172 /* The new range breaks the old one in two pieces,
173 so we have to use the second new range. */
174 new_asr2->start = right->start;
175 new_asr2->end = right->end;
176 left = new_asr2;
177 insert_range (before, left);
178 new_asr2 = NULL;
179 }
180 right->start = caller->end + 1;
181 }
182 if (left)
183 {
184 left->end = caller->start - 1;
185 }
186
187 out:
188 if (new_asr)
34b47c38 189 free (new_asr);
c906108c 190 if (new_asr2)
34b47c38 191 free (new_asr2);
c906108c
SS
192}
193
194/* Free T and all subtrees. */
195
196static void
197free_search_tree (ADDR_RANGE_TREE *t)
198{
199 if (t != NULL)
200 {
201 free_search_tree (t->lower);
202 free_search_tree (t->higher);
203 free (t);
204 }
205}
206
207/* Subroutine of build_search_tree to recursively build a balanced tree.
208 ??? It's not an optimum tree though. */
209
210static ADDR_RANGE_TREE *
211build_tree_1 (ADDR_SUBRANGE **asrtab, unsigned int n)
212{
213 unsigned int mid = n / 2;
214 ADDR_RANGE_TREE *t;
215
216 if (n == 0)
217 return NULL;
218 t = (ADDR_RANGE_TREE *) xmalloc (sizeof (ADDR_RANGE_TREE));
219 t->start = asrtab[mid]->start;
220 t->end = asrtab[mid]->end;
221 if (mid != 0)
222 t->lower = build_tree_1 (asrtab, mid);
223 else
224 t->lower = NULL;
225 if (n > mid + 1)
226 t->higher = build_tree_1 (asrtab + mid + 1, n - mid - 1);
227 else
228 t->higher = NULL;
229 return t;
230}
231
232/* Build a search tree for address range AR. */
233
234static void
235build_search_tree (ADDR_RANGE *ar)
236{
237 /* ??? Simple version for now. */
238 ADDR_SUBRANGE *asr,**asrtab;
239 unsigned int i, n;
240
241 for (n = 0, asr = ar->ranges; asr != NULL; ++n, asr = asr->next)
242 continue;
243 asrtab = (ADDR_SUBRANGE **) xmalloc (n * sizeof (ADDR_SUBRANGE *));
244 for (i = 0, asr = ar->ranges; i < n; ++i, asr = asr->next)
245 asrtab[i] = asr;
246 ar->range_tree = build_tree_1 (asrtab, n);
247 free (asrtab);
248}
249
ef986697
SH
250INLINE_SIM_ARANGE\
251(void)
c906108c
SS
252sim_addr_range_add (ADDR_RANGE *ar, address_word start, address_word end)
253{
254 frob_range (ar, start, end, 0);
255
256 /* Rebuild the search tree. */
257 /* ??? Instead of rebuilding it here it could be done in a module resume
258 handler, say by first checking for a `changed' flag, assuming of course
259 this would never be done while the simulation is running. */
260 free_search_tree (ar->range_tree);
261 build_search_tree (ar);
262}
263
ef986697
SH
264INLINE_SIM_ARANGE\
265(void)
c906108c
SS
266sim_addr_range_delete (ADDR_RANGE *ar, address_word start, address_word end)
267{
268 frob_range (ar, start, end, 1);
269
270 /* Rebuild the search tree. */
271 /* ??? Instead of rebuilding it here it could be done in a module resume
272 handler, say by first checking for a `changed' flag, assuming of course
273 this would never be done while the simulation is running. */
274 free_search_tree (ar->range_tree);
275 build_search_tree (ar);
276}
277
ef986697
SH
278INLINE_SIM_ARANGE\
279(int)
c906108c
SS
280sim_addr_range_hit_p (ADDR_RANGE *ar, address_word addr)
281{
282 ADDR_RANGE_TREE *t = ar->range_tree;
283
284 while (t != NULL)
285 {
286 if (addr < t->start)
287 t = t->lower;
288 else if (addr > t->end)
289 t = t->higher;
290 else
291 return 1;
292 }
293 return 0;
294}
295
ef986697 296#endif /* _SIM_ARANGE_C_ */
This page took 1.033606 seconds and 4 git commands to generate.