2 Copyright (C) 1998-2014 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 /* Tell sim-arange.h it's us. */
23 #include "libiberty.h"
24 #include "sim-basics.h"
25 #include "sim-assert.h"
35 #define DEFINE_INLINE_P (! defined (SIM_ARANGE_C_INCLUDED))
36 #define DEFINE_NON_INLINE_P defined (SIM_ARANGE_C_INCLUDED)
38 #if DEFINE_NON_INLINE_P
43 insert_range (ADDR_SUBRANGE **pos, ADDR_SUBRANGE *asr)
52 delete_range (ADDR_SUBRANGE **thisasrp)
54 ADDR_SUBRANGE *thisasr;
57 *thisasrp = thisasr->next;
62 /* Add or delete an address range.
63 This code was borrowed from linux's locks.c:posix_lock_file().
64 ??? Todo: Given our simpler needs this could be simplified
65 (split into two fns). */
68 frob_range (ADDR_RANGE *ar, address_word start, address_word end, int delete_p)
71 ADDR_SUBRANGE *new_asr, *new_asr2;
72 ADDR_SUBRANGE *left = NULL;
73 ADDR_SUBRANGE *right = NULL;
74 ADDR_SUBRANGE **before;
75 ADDR_SUBRANGE init_caller;
76 ADDR_SUBRANGE *caller = &init_caller;
79 memset (caller, 0, sizeof (ADDR_SUBRANGE));
80 new_asr = ZALLOC (ADDR_SUBRANGE);
81 new_asr2 = ZALLOC (ADDR_SUBRANGE);
83 caller->start = start;
87 while ((asr = *before) != NULL)
91 /* Try next range if current range preceeds new one and not
92 adjacent or overlapping. */
93 if (asr->end < caller->start - 1)
96 /* Break out if new range preceeds current one and not
97 adjacent or overlapping. */
98 if (asr->start > caller->end + 1)
101 /* If we come here, the new and current ranges are adjacent or
102 overlapping. Make one range yielding from the lower start address
103 of both ranges to the higher end address. */
104 if (asr->start > caller->start)
105 asr->start = caller->start;
107 caller->start = asr->start;
108 if (asr->end < caller->end)
109 asr->end = caller->end;
111 caller->end = asr->end;
115 delete_range (before);
121 else /* deleting a range */
123 /* Try next range if current range preceeds new one. */
124 if (asr->end < caller->start)
127 /* Break out if new range preceeds current one. */
128 if (asr->start > caller->end)
133 if (asr->start < caller->start)
136 /* If the next range in the list has a higher end
137 address than the new one, insert the new one here. */
138 if (asr->end > caller->end)
143 if (asr->start >= caller->start)
145 /* The new range completely replaces an old
146 one (This may happen several times). */
149 delete_range (before);
153 /* Replace the old range with the new one. */
154 asr->start = caller->start;
155 asr->end = caller->end;
161 /* Go on to next range. */
170 new_asr->start = caller->start;
171 new_asr->end = caller->end;
172 insert_range (before, new_asr);
179 /* The new range breaks the old one in two pieces,
180 so we have to use the second new range. */
181 new_asr2->start = right->start;
182 new_asr2->end = right->end;
184 insert_range (before, left);
187 right->start = caller->end + 1;
191 left->end = caller->start - 1;
201 /* Free T and all subtrees. */
204 free_search_tree (ADDR_RANGE_TREE *t)
208 free_search_tree (t->lower);
209 free_search_tree (t->higher);
214 /* Subroutine of build_search_tree to recursively build a balanced tree.
215 ??? It's not an optimum tree though. */
217 static ADDR_RANGE_TREE *
218 build_tree_1 (ADDR_SUBRANGE **asrtab, unsigned int n)
220 unsigned int mid = n / 2;
225 t = (ADDR_RANGE_TREE *) xmalloc (sizeof (ADDR_RANGE_TREE));
226 t->start = asrtab[mid]->start;
227 t->end = asrtab[mid]->end;
229 t->lower = build_tree_1 (asrtab, mid);
233 t->higher = build_tree_1 (asrtab + mid + 1, n - mid - 1);
239 /* Build a search tree for address range AR. */
242 build_search_tree (ADDR_RANGE *ar)
244 /* ??? Simple version for now. */
245 ADDR_SUBRANGE *asr,**asrtab;
248 for (n = 0, asr = ar->ranges; asr != NULL; ++n, asr = asr->next)
250 asrtab = (ADDR_SUBRANGE **) xmalloc (n * sizeof (ADDR_SUBRANGE *));
251 for (i = 0, asr = ar->ranges; i < n; ++i, asr = asr->next)
253 ar->range_tree = build_tree_1 (asrtab, n);
258 sim_addr_range_add (ADDR_RANGE *ar, address_word start, address_word end)
260 frob_range (ar, start, end, 0);
262 /* Rebuild the search tree. */
263 /* ??? Instead of rebuilding it here it could be done in a module resume
264 handler, say by first checking for a `changed' flag, assuming of course
265 this would never be done while the simulation is running. */
266 free_search_tree (ar->range_tree);
267 build_search_tree (ar);
271 sim_addr_range_delete (ADDR_RANGE *ar, address_word start, address_word end)
273 frob_range (ar, start, end, 1);
275 /* Rebuild the search tree. */
276 /* ??? Instead of rebuilding it here it could be done in a module resume
277 handler, say by first checking for a `changed' flag, assuming of course
278 this would never be done while the simulation is running. */
279 free_search_tree (ar->range_tree);
280 build_search_tree (ar);
283 #endif /* DEFINE_NON_INLINE_P */
287 SIM_ARANGE_INLINE int
288 sim_addr_range_hit_p (ADDR_RANGE *ar, address_word addr)
290 ADDR_RANGE_TREE *t = ar->range_tree;
296 else if (addr > t->end)
304 #endif /* DEFINE_INLINE_P */