scc  2022.4.0
SystemC components library
range_lut.h
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 
17 #ifndef _RANGE_LUT_H_
18 #define _RANGE_LUT_H_
19 
20 #include <exception>
21 #include <iomanip>
22 #include <iostream>
23 #include <map>
24 #include <sstream>
25 #include <stdexcept>
26 #include <string>
27 
33 namespace util {
37 template <typename T> class range_lut {
38 public:
40  enum entry_type { BEGIN_RANGE = 1, END_RANGE = 2, SINGLE_BYTE_RANGE = 3 };
42  struct lut_entry {
43  T index;
44  entry_type type;
45  };
46 
62  void addEntry(T i, uint64_t base_addr, uint64_t size);
69  bool removeEntry(T i);
75  size_t size() const { return m_size; }
79  void clear() {
80  m_lut.clear();
81  m_size = 0;
82  }
89  inline T getEntry(uint64_t addr) const {
90  auto iter = m_lut.lower_bound(addr);
91  return (iter != m_lut.end() && (iter->second.type == END_RANGE || iter->first == addr)) ? iter->second.index : null_entry;
92  }
96  void validate() const;
103  std::string toString() const;
105  const T null_entry;
106 
107  using const_iterator = typename std::map<uint64_t, lut_entry>::const_iterator;
108 
109  const_iterator begin() const { return m_lut.begin(); }
110 
111  const_iterator end() const { return m_lut.end(); }
112 
113 protected:
114  // Loki::AssocVector<uint64_t, lut_entry> m_lut;
115  std::map<uint64_t, lut_entry> m_lut{};
116  size_t m_size{0};
117 };
118 
126 template <typename T> std::ostream& operator<<(std::ostream& os, range_lut<T>& lut) {
127  os << lut.toString();
128  return os;
129 }
130 
131 template <typename T> inline void range_lut<T>::addEntry(T i, uint64_t base_addr, uint64_t size) {
132  auto iter = m_lut.find(base_addr);
133  if(iter != m_lut.end() && iter->second.index != null_entry)
134  throw std::runtime_error("range already mapped");
135 
136  auto eaddr = base_addr + size - 1;
137  if(eaddr < base_addr)
138  throw std::runtime_error("address wrap-around occurred");
139 
140  m_lut[base_addr] = lut_entry{i, size > 1 ? BEGIN_RANGE : SINGLE_BYTE_RANGE};
141  if(size > 1)
142  m_lut[eaddr] = lut_entry{i, END_RANGE};
143  ++m_size;
144 }
145 
146 template <typename T> inline bool range_lut<T>::removeEntry(T i) {
147  auto start = m_lut.begin();
148  while(start->second.index != i && start != m_lut.end())
149  start++;
150  if(start != m_lut.end()) {
151  if(start->second.type == SINGLE_BYTE_RANGE) {
152  m_lut.erase(start);
153  } else {
154  auto end = start;
155  end++;
156  end++;
157  m_lut.erase(start, end);
158  }
159  --m_size;
160  return true;
161  }
162  return false;
163 }
164 
165 template <typename T> inline void range_lut<T>::validate() const {
166  auto mapped = false;
167  for(auto iter = m_lut.begin(); iter != m_lut.end(); iter++) {
168  switch(iter->second.type) {
169  case SINGLE_BYTE_RANGE:
170  if(iter->second.index != null_entry && mapped)
171  throw std::runtime_error("range overlap: begin range while in mapped range");
172 
173  break;
174  case BEGIN_RANGE:
175  if(iter->second.index != null_entry) {
176  if(mapped) {
177  throw std::runtime_error("range overlap: begin range while in mapped range");
178  }
179  mapped = true;
180  }
181  break;
182  case END_RANGE:
183  if(!mapped) {
184  throw std::runtime_error("range overlap: end range while in unmapped region");
185  }
186  mapped = false;
187  break;
188  }
189  }
190 }
191 
192 template <typename T> inline std::string range_lut<T>::toString() const {
193  std::ostringstream buf;
194  for(auto iter = m_lut.begin(); iter != m_lut.end(); ++iter) {
195  switch(iter->second.type) {
196  case BEGIN_RANGE:
197  if(iter->second.index != null_entry) {
198  buf << " from 0x" << std::setw(sizeof(uint64_t) * 2) << std::setfill('0') << std::uppercase << std::hex << iter->first
199  << std::dec;
200  }
201  break;
202  case END_RANGE:
203  buf << " to 0x" << std::setw(sizeof(uint64_t) * 2) << std::setfill('0') << std::uppercase << std::hex << iter->first << std::dec
204  << " as " << iter->second->index << std::endl;
205  }
206  }
207  return buf.str();
208 }
209 } // namespace util
211 #endif /* _RANGE_LUT_H_ */
range based lookup table
Definition: range_lut.h:37
void clear()
Definition: range_lut.h:79
std::string toString() const
Definition: range_lut.h:192
size_t size() const
Definition: range_lut.h:75
void addEntry(T i, uint64_t base_addr, uint64_t size)
Definition: range_lut.h:131
range_lut(T null_entry)
Definition: range_lut.h:52
void validate() const
Definition: range_lut.h:165
bool removeEntry(T i)
Definition: range_lut.h:146
const T null_entry
the null entry
Definition: range_lut.h:105
T getEntry(uint64_t addr) const
Definition: range_lut.h:89
entry_type
the type of lut entry
Definition: range_lut.h:40
SCC common utilities.
Definition: bit_field.h:30
std::ostream & operator<<(std::ostream &os, range_lut< T > &lut)
Definition: range_lut.h:126
the lut entry
Definition: range_lut.h:42