A SystemC productivity library for virtual platform development utilizing SCV and TLM2.0 https://www.minres.com/#opensource

range_lut.h 5.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. /*******************************************************************************
  2. * Copyright 2017, 2018 MINRES Technologies GmbH
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *******************************************************************************/
  16. #ifndef _RANGE_LUT_H_
  17. #define _RANGE_LUT_H_
  18. #include <exception>
  19. #include <iomanip>
  20. #include <iostream>
  21. #include <map>
  22. #include <sstream>
  23. #include <stdexcept>
  24. #include <string>
  25. namespace util {
  26. /**
  27. * range based lookup table
  28. */
  29. template <typename T> class range_lut {
  30. //! the type of lut entry
  31. enum entry_type { BEGIN_RANGE = 1, END_RANGE = 2, SINGLE_BYTE_RANGE = 3 };
  32. //! the lut entry
  33. struct lut_entry {
  34. T index;
  35. entry_type type;
  36. };
  37. public:
  38. /**
  39. * constructor or the lookup table
  40. *
  41. * @param null_entry the entry to be used for empty slots
  42. */
  43. range_lut(T null_entry)
  44. : null_entry(null_entry) {}
  45. /**
  46. * add an T to the lut covering the range starting at base_addr until
  47. * base_addr+size-1
  48. *
  49. * @param i the entry
  50. * @param base_addr the base address
  51. * @param size the size of the occupied range
  52. */
  53. void addEntry(T i, uint64_t base_addr, uint64_t size);
  54. /**
  55. * remove an entry with value i of type T
  56. *
  57. * @param i the entry to be found
  58. * @return true if the entry is found and removed, false otherwise
  59. */
  60. bool removeEntry(T i);
  61. /**
  62. * get number of entries in the lookup table
  63. *
  64. * @return the size of the underlying container
  65. */
  66. size_t size() { return m_size; }
  67. /**
  68. * remove all entries from the lut
  69. */
  70. void clear() { m_lut.clear(); }
  71. /**
  72. * get the entry T associated with a given address
  73. *
  74. * @param addr the address
  75. * @return the entry belonging to the address
  76. */
  77. inline T getEntry(uint64_t addr) {
  78. auto iter = m_lut.lower_bound(addr);
  79. return (iter != m_lut.end() && (iter->second.type == END_RANGE || iter->first == addr)) ? iter->second.index
  80. : null_entry;
  81. }
  82. /**
  83. * validate the lookup table wrt. overlaps
  84. */
  85. void validate();
  86. /**
  87. * create a textual representation of the address map (address range->entry
  88. * association)
  89. *
  90. * @return
  91. */
  92. std::string toString();
  93. //!the null entry
  94. const T null_entry;
  95. protected:
  96. // Loki::AssocVector<uint64_t, lut_entry> m_lut;
  97. std::map<uint64_t, lut_entry> m_lut;
  98. size_t m_size;
  99. };
  100. /**
  101. * overloaded stream operator
  102. *
  103. * @param os the output stream
  104. * @return the stream
  105. */
  106. template <typename T> std::ostream &operator<<(std::ostream &os, range_lut<T> &lut) {
  107. os << lut.toString();
  108. return os;
  109. }
  110. template <typename T> inline void range_lut<T>::addEntry(T i, uint64_t base_addr, uint64_t size) {
  111. auto iter = m_lut.find(base_addr);
  112. if (iter != m_lut.end() && iter->second.index != null_entry) throw std::runtime_error("range already mapped");
  113. auto eaddr = base_addr + size - 1;
  114. if (eaddr < base_addr) throw std::runtime_error("address wrap-around occurred");
  115. m_lut[base_addr] = lut_entry{i, size > 1 ? BEGIN_RANGE : SINGLE_BYTE_RANGE};
  116. if (size > 1) m_lut[eaddr] = lut_entry{i, END_RANGE};
  117. ++m_size;
  118. }
  119. template <typename T> inline bool range_lut<T>::removeEntry(T i) {
  120. auto start = m_lut.begin();
  121. while (start->second.index != i && start != m_lut.end()) start++;
  122. if (start != m_lut.end()) {
  123. if (start->second.type == SINGLE_BYTE_RANGE) {
  124. m_lut.erase(start);
  125. } else {
  126. auto end = start;
  127. end++;
  128. end++;
  129. m_lut.erase(start, end);
  130. }
  131. --m_size;
  132. return true;
  133. }
  134. return false;
  135. }
  136. template <typename T> inline void range_lut<T>::validate() {
  137. auto mapped = false;
  138. for (auto iter = m_lut.begin(); iter != m_lut.end(); iter++) {
  139. switch (iter->second.type) {
  140. case SINGLE_BYTE_RANGE:
  141. if (iter->second.index != null_entry && mapped)
  142. throw std::runtime_error("range overlap: begin range while in mapped range");
  143. break;
  144. case BEGIN_RANGE:
  145. if (iter->second.index != null_entry) {
  146. if (mapped) {
  147. throw std::runtime_error("range overlap: begin range while in mapped range");
  148. }
  149. mapped = true;
  150. }
  151. break;
  152. case END_RANGE:
  153. if (!mapped) {
  154. throw std::runtime_error("range overlap: end range while in unmapped region");
  155. }
  156. mapped = false;
  157. break;
  158. }
  159. }
  160. }
  161. template <typename T> inline std::string range_lut<T>::toString() {
  162. std::ostringstream buf;
  163. for (auto iter = m_lut.begin(); iter != m_lut.end(); ++iter) {
  164. switch (iter->second.type) {
  165. case BEGIN_RANGE:
  166. if (iter->second.index != null_entry) {
  167. buf << " from 0x" << std::setw(sizeof(uint64_t) * 2) << std::setfill('0') << std::uppercase << std::hex
  168. << iter->first << std::dec;
  169. }
  170. break;
  171. case END_RANGE:
  172. buf << " to 0x" << std::setw(sizeof(uint64_t) * 2) << std::setfill('0') << std::uppercase << std::hex
  173. << iter->first << std::dec << " as " << iter->second->index << std::endl;
  174. }
  175. }
  176. return buf.str();
  177. }
  178. } // namespace util
  179. #endif /* _RANGE_LUT_H_ */