📄 sim-arange.c
字号:
/* Address ranges. Copyright (C) 1998 Free Software Foundation, Inc. Contributed by Cygnus Solutions.This file is part of the GNU Simulators.This program is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2, or (at your option)any later version.This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public License alongwith this program; if not, write to the Free Software Foundation, Inc.,59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *//* Tell sim-arange.h it's us. */#define SIM_ARANGE_C#include "libiberty.h"#include "sim-basics.h"#include "sim-assert.h"#ifdef HAVE_STDLIB_H#include <stdlib.h>#endif#ifdef HAVE_STRING_H#include <string.h>#endif#define DEFINE_INLINE_P (! defined (SIM_ARANGE_C_INCLUDED))#define DEFINE_NON_INLINE_P defined (SIM_ARANGE_C_INCLUDED)#if DEFINE_NON_INLINE_P/* Insert a range. */static voidinsert_range (ADDR_SUBRANGE **pos, ADDR_SUBRANGE *asr){ asr->next = *pos; *pos = asr;}/* Delete a range. */static voiddelete_range (ADDR_SUBRANGE **thisasrp){ ADDR_SUBRANGE *thisasr; thisasr = *thisasrp; *thisasrp = thisasr->next; free (thisasr);}/* Add or delete an address range. This code was borrowed from linux's locks.c:posix_lock_file(). ??? Todo: Given our simpler needs this could be simplified (split into two fns). */static voidfrob_range (ADDR_RANGE *ar, address_word start, address_word end, int delete_p){ ADDR_SUBRANGE *asr; ADDR_SUBRANGE *new_asr, *new_asr2; ADDR_SUBRANGE *left = NULL; ADDR_SUBRANGE *right = NULL; ADDR_SUBRANGE **before; ADDR_SUBRANGE init_caller; ADDR_SUBRANGE *caller = &init_caller; int added_p = 0; memset (caller, 0, sizeof (ADDR_SUBRANGE)); new_asr = ZALLOC (ADDR_SUBRANGE); new_asr2 = ZALLOC (ADDR_SUBRANGE); caller->start = start; caller->end = end; before = &ar->ranges; while ((asr = *before) != NULL) { if (! delete_p) { /* Try next range if current range preceeds new one and not adjacent or overlapping. */ if (asr->end < caller->start - 1) goto next_range; /* Break out if new range preceeds current one and not adjacent or overlapping. */ if (asr->start > caller->end + 1) break; /* If we come here, the new and current ranges are adjacent or overlapping. Make one range yielding from the lower start address of both ranges to the higher end address. */ if (asr->start > caller->start) asr->start = caller->start; else caller->start = asr->start; if (asr->end < caller->end) asr->end = caller->end; else caller->end = asr->end; if (added_p) { delete_range (before); continue; } caller = asr; added_p = 1; } else /* deleting a range */ { /* Try next range if current range preceeds new one. */ if (asr->end < caller->start) goto next_range; /* Break out if new range preceeds current one. */ if (asr->start > caller->end) break; added_p = 1; if (asr->start < caller->start) left = asr; /* If the next range in the list has a higher end address than the new one, insert the new one here. */ if (asr->end > caller->end) { right = asr; break; } if (asr->start >= caller->start) { /* The new range completely replaces an old one (This may happen several times). */ if (added_p) { delete_range (before); continue; } /* Replace the old range with the new one. */ asr->start = caller->start; asr->end = caller->end; caller = asr; added_p = 1; } } /* Go on to next range. */ next_range: before = &asr->next; } if (!added_p) { if (delete_p) goto out; new_asr->start = caller->start; new_asr->end = caller->end; insert_range (before, new_asr); new_asr = NULL; } if (right) { if (left == right) { /* The new range breaks the old one in two pieces, so we have to use the second new range. */ new_asr2->start = right->start; new_asr2->end = right->end; left = new_asr2; insert_range (before, left); new_asr2 = NULL; } right->start = caller->end + 1; } if (left) { left->end = caller->start - 1; } out: if (new_asr) free(new_asr); if (new_asr2) free(new_asr2);}/* Free T and all subtrees. */static voidfree_search_tree (ADDR_RANGE_TREE *t){ if (t != NULL) { free_search_tree (t->lower); free_search_tree (t->higher); free (t); }}/* Subroutine of build_search_tree to recursively build a balanced tree. ??? It's not an optimum tree though. */static ADDR_RANGE_TREE *build_tree_1 (ADDR_SUBRANGE **asrtab, unsigned int n){ unsigned int mid = n / 2; ADDR_RANGE_TREE *t; if (n == 0) return NULL; t = (ADDR_RANGE_TREE *) xmalloc (sizeof (ADDR_RANGE_TREE)); t->start = asrtab[mid]->start; t->end = asrtab[mid]->end; if (mid != 0) t->lower = build_tree_1 (asrtab, mid); else t->lower = NULL; if (n > mid + 1) t->higher = build_tree_1 (asrtab + mid + 1, n - mid - 1); else t->higher = NULL; return t;}/* Build a search tree for address range AR. */static voidbuild_search_tree (ADDR_RANGE *ar){ /* ??? Simple version for now. */ ADDR_SUBRANGE *asr,**asrtab; unsigned int i, n; for (n = 0, asr = ar->ranges; asr != NULL; ++n, asr = asr->next) continue; asrtab = (ADDR_SUBRANGE **) xmalloc (n * sizeof (ADDR_SUBRANGE *)); for (i = 0, asr = ar->ranges; i < n; ++i, asr = asr->next) asrtab[i] = asr; ar->range_tree = build_tree_1 (asrtab, n); free (asrtab);}voidsim_addr_range_add (ADDR_RANGE *ar, address_word start, address_word end){ frob_range (ar, start, end, 0); /* Rebuild the search tree. */ /* ??? Instead of rebuilding it here it could be done in a module resume handler, say by first checking for a `changed' flag, assuming of course this would never be done while the simulation is running. */ free_search_tree (ar->range_tree); build_search_tree (ar);}voidsim_addr_range_delete (ADDR_RANGE *ar, address_word start, address_word end){ frob_range (ar, start, end, 1); /* Rebuild the search tree. */ /* ??? Instead of rebuilding it here it could be done in a module resume handler, say by first checking for a `changed' flag, assuming of course this would never be done while the simulation is running. */ free_search_tree (ar->range_tree); build_search_tree (ar);}#endif /* DEFINE_NON_INLINE_P */#if DEFINE_INLINE_PSIM_ARANGE_INLINE intsim_addr_range_hit_p (ADDR_RANGE *ar, address_word addr){ ADDR_RANGE_TREE *t = ar->range_tree; while (t != NULL) { if (addr < t->start) t = t->lower; else if (addr > t->end) t = t->higher; else return 1; } return 0;}#endif /* DEFINE_INLINE_P */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -