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