Fix whitespace snafu in tc-riscv.c
[binutils-gdb.git] / sim / common / sim-arange.c
blobf570a15c7807f3b5f6c4a030af842cf9920fadb5
1 /* Address ranges.
2 Copyright (C) 1998-2023 Free Software Foundation, Inc.
3 Contributed by Cygnus Solutions.
5 This file is part of the GNU Simulators.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
20 #ifndef _SIM_ARANGE_C_
21 #define _SIM_ARANGE_C_
23 /* This must come before any other includes. */
24 #include "defs.h"
26 #include <stdlib.h>
27 #include <string.h>
29 #include "libiberty.h"
31 #include "sim-basics.h"
32 #include "sim-arange.h"
34 /* Insert a range. */
36 static void
37 insert_range (ADDR_SUBRANGE **pos, ADDR_SUBRANGE *asr)
39 asr->next = *pos;
40 *pos = asr;
43 /* Delete a range. */
45 static void
46 delete_range (ADDR_SUBRANGE **thisasrp)
48 ADDR_SUBRANGE *thisasr;
50 thisasr = *thisasrp;
51 *thisasrp = thisasr->next;
53 free (thisasr);
56 /* Add or delete an address range.
57 This code was borrowed from linux's locks.c:posix_lock_file().
58 ??? Todo: Given our simpler needs this could be simplified
59 (split into two fns). */
61 static void
62 frob_range (ADDR_RANGE *ar, address_word start, address_word end, int delete_p)
64 ADDR_SUBRANGE *asr;
65 ADDR_SUBRANGE *new_asr, *new_asr2;
66 ADDR_SUBRANGE *left = NULL;
67 ADDR_SUBRANGE *right = NULL;
68 ADDR_SUBRANGE **before;
69 ADDR_SUBRANGE init_caller;
70 ADDR_SUBRANGE *caller = &init_caller;
71 int added_p = 0;
73 memset (caller, 0, sizeof (ADDR_SUBRANGE));
74 new_asr = ZALLOC (ADDR_SUBRANGE);
75 new_asr2 = ZALLOC (ADDR_SUBRANGE);
77 caller->start = start;
78 caller->end = end;
79 before = &ar->ranges;
81 while ((asr = *before) != NULL)
83 if (! delete_p)
85 /* Try next range if current range preceeds new one and not
86 adjacent or overlapping. */
87 if (asr->end < caller->start - 1)
88 goto next_range;
90 /* Break out if new range preceeds current one and not
91 adjacent or overlapping. */
92 if (asr->start > caller->end + 1)
93 break;
95 /* If we come here, the new and current ranges are adjacent or
96 overlapping. Make one range yielding from the lower start address
97 of both ranges to the higher end address. */
98 if (asr->start > caller->start)
99 asr->start = caller->start;
100 else
101 caller->start = asr->start;
102 if (asr->end < caller->end)
103 asr->end = caller->end;
104 else
105 caller->end = asr->end;
107 if (added_p)
109 delete_range (before);
110 continue;
112 caller = asr;
113 added_p = 1;
115 else /* deleting a range */
117 /* Try next range if current range preceeds new one. */
118 if (asr->end < caller->start)
119 goto next_range;
121 /* Break out if new range preceeds current one. */
122 if (asr->start > caller->end)
123 break;
125 added_p = 1;
127 if (asr->start < caller->start)
128 left = asr;
130 /* If the next range in the list has a higher end
131 address than the new one, insert the new one here. */
132 if (asr->end > caller->end)
134 right = asr;
135 break;
137 if (asr->start >= caller->start)
139 /* The new range completely replaces an old
140 one (This may happen several times). */
141 if (added_p)
143 delete_range (before);
144 continue;
147 /* Replace the old range with the new one. */
148 asr->start = caller->start;
149 asr->end = caller->end;
150 caller = asr;
151 added_p = 1;
155 /* Go on to next range. */
156 next_range:
157 before = &asr->next;
160 if (!added_p)
162 if (delete_p)
163 goto out;
164 new_asr->start = caller->start;
165 new_asr->end = caller->end;
166 insert_range (before, new_asr);
167 new_asr = NULL;
169 if (right)
171 if (left == right)
173 /* The new range breaks the old one in two pieces,
174 so we have to use the second new range. */
175 new_asr2->start = right->start;
176 new_asr2->end = right->end;
177 left = new_asr2;
178 insert_range (before, left);
179 new_asr2 = NULL;
181 right->start = caller->end + 1;
183 if (left)
185 left->end = caller->start - 1;
188 out:
189 if (new_asr)
190 free (new_asr);
191 if (new_asr2)
192 free (new_asr2);
195 /* Free T and all subtrees. */
197 static void
198 free_search_tree (ADDR_RANGE_TREE *t)
200 if (t != NULL)
202 free_search_tree (t->lower);
203 free_search_tree (t->higher);
204 free (t);
208 /* Subroutine of build_search_tree to recursively build a balanced tree.
209 ??? It's not an optimum tree though. */
211 static ADDR_RANGE_TREE *
212 build_tree_1 (ADDR_SUBRANGE **asrtab, unsigned int n)
214 unsigned int mid = n / 2;
215 ADDR_RANGE_TREE *t;
217 if (n == 0)
218 return NULL;
219 t = (ADDR_RANGE_TREE *) xmalloc (sizeof (ADDR_RANGE_TREE));
220 t->start = asrtab[mid]->start;
221 t->end = asrtab[mid]->end;
222 if (mid != 0)
223 t->lower = build_tree_1 (asrtab, mid);
224 else
225 t->lower = NULL;
226 if (n > mid + 1)
227 t->higher = build_tree_1 (asrtab + mid + 1, n - mid - 1);
228 else
229 t->higher = NULL;
230 return t;
233 /* Build a search tree for address range AR. */
235 static void
236 build_search_tree (ADDR_RANGE *ar)
238 /* ??? Simple version for now. */
239 ADDR_SUBRANGE *asr,**asrtab;
240 unsigned int i, n;
242 for (n = 0, asr = ar->ranges; asr != NULL; ++n, asr = asr->next)
243 continue;
244 asrtab = (ADDR_SUBRANGE **) xmalloc (n * sizeof (ADDR_SUBRANGE *));
245 for (i = 0, asr = ar->ranges; i < n; ++i, asr = asr->next)
246 asrtab[i] = asr;
247 ar->range_tree = build_tree_1 (asrtab, n);
248 free (asrtab);
251 INLINE_SIM_ARANGE\
252 (void)
253 sim_addr_range_add (ADDR_RANGE *ar, address_word start, address_word end)
255 frob_range (ar, start, end, 0);
257 /* Rebuild the search tree. */
258 /* ??? Instead of rebuilding it here it could be done in a module resume
259 handler, say by first checking for a `changed' flag, assuming of course
260 this would never be done while the simulation is running. */
261 free_search_tree (ar->range_tree);
262 build_search_tree (ar);
265 INLINE_SIM_ARANGE\
266 (void)
267 sim_addr_range_delete (ADDR_RANGE *ar, address_word start, address_word end)
269 frob_range (ar, start, end, 1);
271 /* Rebuild the search tree. */
272 /* ??? Instead of rebuilding it here it could be done in a module resume
273 handler, say by first checking for a `changed' flag, assuming of course
274 this would never be done while the simulation is running. */
275 free_search_tree (ar->range_tree);
276 build_search_tree (ar);
279 INLINE_SIM_ARANGE\
280 (int)
281 sim_addr_range_hit_p (ADDR_RANGE *ar, address_word addr)
283 ADDR_RANGE_TREE *t = ar->range_tree;
285 while (t != NULL)
287 if (addr < t->start)
288 t = t->lower;
289 else if (addr > t->end)
290 t = t->higher;
291 else
292 return 1;
294 return 0;
297 #endif /* _SIM_ARANGE_C_ */