2 Copyright (C) 1998 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 2, or (at your option)
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 along
18 with this program; if not, write to the Free Software Foundation, Inc.,
19 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
21 /* Tell sim-arange.h it's us. */
24 #include "libiberty.h"
25 #include "sim-basics.h"
26 #include "sim-assert.h"
36 #define DEFINE_INLINE_P (! defined (SIM_ARANGE_C_INCLUDED))
37 #define DEFINE_NON_INLINE_P defined (SIM_ARANGE_C_INCLUDED)
39 #if DEFINE_NON_INLINE_P
44 insert_range (ADDR_SUBRANGE
**pos
, ADDR_SUBRANGE
*asr
)
53 delete_range (ADDR_SUBRANGE
**thisasrp
)
55 ADDR_SUBRANGE
*thisasr
;
58 *thisasrp
= thisasr
->next
;
63 /* Add or delete an address range.
64 This code was borrowed from linux's locks.c:posix_lock_file().
65 ??? Todo: Given our simpler needs this could be simplified
66 (split into two fns). */
69 frob_range (ADDR_RANGE
*ar
, address_word start
, address_word end
, int delete_p
)
72 ADDR_SUBRANGE
*new_asr
, *new_asr2
;
73 ADDR_SUBRANGE
*left
= NULL
;
74 ADDR_SUBRANGE
*right
= NULL
;
75 ADDR_SUBRANGE
**before
;
76 ADDR_SUBRANGE init_caller
;
77 ADDR_SUBRANGE
*caller
= &init_caller
;
80 memset (caller
, 0, sizeof (ADDR_SUBRANGE
));
81 new_asr
= ZALLOC (ADDR_SUBRANGE
);
82 new_asr2
= ZALLOC (ADDR_SUBRANGE
);
84 caller
->start
= start
;
88 while ((asr
= *before
) != NULL
)
92 /* Try next range if current range preceeds new one and not
93 adjacent or overlapping. */
94 if (asr
->end
< caller
->start
- 1)
97 /* Break out if new range preceeds current one and not
98 adjacent or overlapping. */
99 if (asr
->start
> caller
->end
+ 1)
102 /* If we come here, the new and current ranges are adjacent or
103 overlapping. Make one range yielding from the lower start address
104 of both ranges to the higher end address. */
105 if (asr
->start
> caller
->start
)
106 asr
->start
= caller
->start
;
108 caller
->start
= asr
->start
;
109 if (asr
->end
< caller
->end
)
110 asr
->end
= caller
->end
;
112 caller
->end
= asr
->end
;
116 delete_range (before
);
122 else /* deleting a range */
124 /* Try next range if current range preceeds new one. */
125 if (asr
->end
< caller
->start
)
128 /* Break out if new range preceeds current one. */
129 if (asr
->start
> caller
->end
)
134 if (asr
->start
< caller
->start
)
137 /* If the next range in the list has a higher end
138 address than the new one, insert the new one here. */
139 if (asr
->end
> caller
->end
)
144 if (asr
->start
>= caller
->start
)
146 /* The new range completely replaces an old
147 one (This may happen several times). */
150 delete_range (before
);
154 /* Replace the old range with the new one. */
155 asr
->start
= caller
->start
;
156 asr
->end
= caller
->end
;
162 /* Go on to next range. */
171 new_asr
->start
= caller
->start
;
172 new_asr
->end
= caller
->end
;
173 insert_range (before
, new_asr
);
180 /* The new range breaks the old one in two pieces,
181 so we have to use the second new range. */
182 new_asr2
->start
= right
->start
;
183 new_asr2
->end
= right
->end
;
185 insert_range (before
, left
);
188 right
->start
= caller
->end
+ 1;
192 left
->end
= caller
->start
- 1;
202 /* Free T and all subtrees. */
205 free_search_tree (ADDR_RANGE_TREE
*t
)
209 free_search_tree (t
->lower
);
210 free_search_tree (t
->higher
);
215 /* Subroutine of build_search_tree to recursively build a balanced tree.
216 ??? It's not an optimum tree though. */
218 static ADDR_RANGE_TREE
*
219 build_tree_1 (ADDR_SUBRANGE
**asrtab
, unsigned int n
)
221 unsigned int mid
= n
/ 2;
226 t
= (ADDR_RANGE_TREE
*) xmalloc (sizeof (ADDR_RANGE_TREE
));
227 t
->start
= asrtab
[mid
]->start
;
228 t
->end
= asrtab
[mid
]->end
;
230 t
->lower
= build_tree_1 (asrtab
, mid
);
234 t
->higher
= build_tree_1 (asrtab
+ mid
+ 1, n
- mid
- 1);
240 /* Build a search tree for address range AR. */
243 build_search_tree (ADDR_RANGE
*ar
)
245 /* ??? Simple version for now. */
246 ADDR_SUBRANGE
*asr
,**asrtab
;
249 for (n
= 0, asr
= ar
->ranges
; asr
!= NULL
; ++n
, asr
= asr
->next
)
251 asrtab
= (ADDR_SUBRANGE
**) xmalloc (n
* sizeof (ADDR_SUBRANGE
*));
252 for (i
= 0, asr
= ar
->ranges
; i
< n
; ++i
, asr
= asr
->next
)
254 ar
->range_tree
= build_tree_1 (asrtab
, n
);
259 sim_addr_range_add (ADDR_RANGE
*ar
, address_word start
, address_word end
)
261 frob_range (ar
, start
, end
, 0);
263 /* Rebuild the search tree. */
264 /* ??? Instead of rebuilding it here it could be done in a module resume
265 handler, say by first checking for a `changed' flag, assuming of course
266 this would never be done while the simulation is running. */
267 free_search_tree (ar
->range_tree
);
268 build_search_tree (ar
);
272 sim_addr_range_delete (ADDR_RANGE
*ar
, address_word start
, address_word end
)
274 frob_range (ar
, start
, end
, 1);
276 /* Rebuild the search tree. */
277 /* ??? Instead of rebuilding it here it could be done in a module resume
278 handler, say by first checking for a `changed' flag, assuming of course
279 this would never be done while the simulation is running. */
280 free_search_tree (ar
->range_tree
);
281 build_search_tree (ar
);
284 #endif /* DEFINE_NON_INLINE_P */
288 SIM_ARANGE_INLINE
int
289 sim_addr_range_hit_p (ADDR_RANGE
*ar
, address_word addr
)
291 ADDR_RANGE_TREE
*t
= ar
->range_tree
;
297 else if (addr
> t
->end
)
305 #endif /* DEFINE_INLINE_P */