1 // Copyright 2017-2019 VMware, Inc.
2 // SPDX-License-Identifier: BSD-2-Clause
3 //
4 // The BSD-2 license (the License) set forth below applies to all parts of the
5 // Cascade project. You may not use this file except in compliance with the
6 // License.
7 //
8 // BSD-2 License
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are met:
12 //
13 // 1. Redistributions of source code must retain the above copyright notice, this
14 // list of conditions and the following disclaimer.
15 //
16 // 2. Redistributions in binary form must reproduce the above copyright notice,
17 // this list of conditions and the following disclaimer in the documentation
18 // and/or other materials provided with the distribution.
19 //
20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND
21 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31 #ifndef CASCADE_SRC_TARGET_CORE_AVMM_VAR_TABLE_H
32 #define CASCADE_SRC_TARGET_CORE_AVMM_VAR_TABLE_H
33
34 #include <cassert>
35 #include <functional>
36 #include <unordered_map>
37 #include "common/bits.h"
38 #include "common/vector.h"
39 #include "verilog/analyze/evaluate.h"
40 #include "verilog/analyze/resolve.h"
41 #include "verilog/ast/ast.h"
42
43 namespace cascade::avmm {
44
45 template <size_t V, typename A, typename T>
46 class VarTable {
47 public:
48 // Row Type:
49 struct Row {
50 size_t begin;
51 size_t elements;
52 size_t bits_per_element;
53 size_t words_per_element;
54 };
55
56 // IO Typedefs:
57 typedef std::function<T(A)> Read;
58 typedef std::function<void(A, T)> Write;
59
60 // Iterator Typedefs:
61 typedef typename std::unordered_map<const Identifier*, const Row>::const_iterator const_iterator;
62
63 // Constructors:
64 VarTable();
65
66 // Configuration Interface:
67 VarTable& set_read(Read read);
68 VarTable& set_write(Write write);
69
70 // Inserts an element into the table.
71 void insert(const Identifier* id);
72 // Returns the number of words in the var table.
73 size_t size() const;
74
75 // Returns a pointer to an element in the table or end on failure
76 const_iterator find(const Identifier* id) const;
77 // Returns a pointer to the beginning of the table
78 const_iterator begin() const;
79 // Returns a pointer ot the end of the table
80 const_iterator end() const;
81
82 // Returns the starting index of this identifier.
83 size_t index(const Identifier* id) const;
84 // Returns the address of the there_are_updates control variable.
85 size_t there_are_updates_index() const;
86 // Returns the address of the apply_update control variable.
87 size_t apply_update_index() const;
88 // Returns the address of the task control variable.
89 size_t there_were_tasks_index() const;
90 // Returns the address of the resume control variable.
91 size_t resume_index() const;
92 // Returns the address of the reset control variable.
93 size_t reset_index() const;
94 // Returns the address of the open_loop control variable.
95 size_t open_loop_index() const;
96 // Returns the address of the feof control variable.
97 size_t feof_index() const;
98 // Reserved for debugging
99 size_t debug_index() const;
100
101 // Reads the value of a control variable
102 T read_control_var(size_t index) const;
103 // Writes the value of a control variable
104 void write_control_var(size_t index, T val);
105
106 // Reads the value of a variable
107 void read_var(size_t slot, const Identifier* id) const;
108 // Writes the value of a scalar variable
109 void write_var(size_t slot, const Identifier* id, const Bits& val);
110 // Writes the value of an array variable
111 void write_var(size_t slot, const Identifier* id, const Vector<Bits>& val);
112
113 private:
114 Read read_;
115 Write write_;
116
117 size_t next_index_;
118 std::unordered_map<const Identifier*, const Row> vtable_;
119 };
120
121 template <size_t V, typename A, typename T>
VarTable()122 inline VarTable<V,A,T>::VarTable() {
123 next_index_ = 0;
124 }
125
126 template <size_t V, typename A, typename T>
set_read(Read read)127 inline VarTable<V,A,T>& VarTable<V,A,T>::set_read(Read read) {
128 read_ = read;
129 return *this;
130 }
131
132 template <size_t V, typename A, typename T>
set_write(Write write)133 inline VarTable<V,A,T>& VarTable<V,A,T>::set_write(Write write) {
134 write_ = write;
135 return *this;
136 }
137
138 template <size_t V, typename A, typename T>
insert(const Identifier * id)139 inline void VarTable<V,A,T>::insert(const Identifier* id) {
140 assert(find(id) == end());
141
142 Row row;
143 row.begin = next_index_;
144 row.elements = 1;
145 for (auto d : Evaluate().get_arity(id)) {
146 row.elements *= d;
147 }
148 const auto* r = Resolve().get_resolution(id);
149 assert(r != nullptr);
150 row.bits_per_element = std::max(Evaluate().get_width(r), Evaluate().get_width(id));
151 row.words_per_element = (row.bits_per_element + std::numeric_limits<T>::digits - 1) / std::numeric_limits<T>::digits;
152
153 vtable_.insert(std::make_pair(id, row));
154 next_index_ += (row.elements * row.words_per_element);
155 }
156
157 template <size_t V, typename A, typename T>
size()158 inline size_t VarTable<V,A,T>::size() const {
159 return debug_index() + 1;
160 }
161
162 template <size_t V, typename A, typename T>
find(const Identifier * id)163 inline typename VarTable<V,A,T>::const_iterator VarTable<V,A,T>::find(const Identifier* id) const {
164 return vtable_.find(id);
165 }
166
167 template <size_t V, typename A, typename T>
begin()168 inline typename VarTable<V,A,T>::const_iterator VarTable<V,A,T>::begin() const {
169 return vtable_.begin();
170 }
171
172 template <size_t V, typename A, typename T>
end()173 inline typename VarTable<V,A,T>::const_iterator VarTable<V,A,T>::end() const {
174 return vtable_.end();
175 }
176
177 template <size_t V, typename A, typename T>
index(const Identifier * id)178 inline size_t VarTable<V,A,T>::index(const Identifier* id) const {
179 const auto itr = vtable_.find(id);
180 assert(itr != vtable_.end());
181 return itr->second.index_;
182 }
183
184 template <size_t V, typename A, typename T>
there_are_updates_index()185 inline size_t VarTable<V,A,T>::there_are_updates_index() const {
186 return next_index_;
187 }
188
189 template <size_t V, typename A, typename T>
apply_update_index()190 inline size_t VarTable<V,A,T>::apply_update_index() const {
191 return next_index_ + 1;
192 }
193
194 template <size_t V, typename A, typename T>
there_were_tasks_index()195 inline size_t VarTable<V,A,T>::there_were_tasks_index() const {
196 return next_index_ + 2;
197 }
198
199 template <size_t V, typename A, typename T>
resume_index()200 inline size_t VarTable<V,A,T>::resume_index() const {
201 return next_index_ + 3;
202 }
203
204 template <size_t V, typename A, typename T>
reset_index()205 inline size_t VarTable<V,A,T>::reset_index() const {
206 return next_index_ + 4;
207 }
208
209 template <size_t V, typename A, typename T>
open_loop_index()210 inline size_t VarTable<V,A,T>::open_loop_index() const {
211 return next_index_ + 5;
212 }
213
214 template <size_t V, typename A, typename T>
feof_index()215 inline size_t VarTable<V,A,T>::feof_index() const {
216 return next_index_ + 6;
217 }
218
219 template <size_t V, typename A, typename T>
debug_index()220 inline size_t VarTable<V,A,T>::debug_index() const {
221 return next_index_ + 7;
222 }
223
224 template <size_t V, typename A, typename T>
read_control_var(size_t index)225 inline T VarTable<V,A,T>::read_control_var(size_t index) const {
226 assert(index >= there_are_updates_index());
227 assert(index <= debug_index());
228 return read_(index);
229 }
230
231 template <size_t V, typename A, typename T>
write_control_var(size_t index,T val)232 inline void VarTable<V,A,T>::write_control_var(size_t index, T val) {
233 assert(index >= there_are_updates_index());
234 assert(index <= debug_index());
235 write_(index, val);
236 }
237
238 template <size_t V, typename A, typename T>
read_var(size_t slot,const Identifier * id)239 inline void VarTable<V,A,T>::read_var(size_t slot, const Identifier* id) const {
240 const auto itr = vtable_.find(id);
241 assert(itr != vtable_.end());
242
243 auto idx = itr->second.begin;
244 for (size_t i = 0; i < itr->second.elements; ++i) {
245 for (size_t j = 0; j < itr->second.words_per_element; ++j) {
246 const volatile auto word = read_((slot << V) | idx);
247 Evaluate().assign_word<T>(id, i, j, word);
248 ++idx;
249 }
250 }
251 }
252
253 template <size_t V, typename A, typename T>
write_var(size_t slot,const Identifier * id,const Bits & val)254 inline void VarTable<V,A,T>::write_var(size_t slot, const Identifier* id, const Bits& val) {
255 const auto itr = vtable_.find(id);
256 assert(itr != vtable_.end());
257 assert(itr->second.elements == 1);
258
259 auto idx = itr->second.begin;
260 for (size_t j = 0; j < itr->second.words_per_element; ++j) {
261 const volatile auto word = val.read_word<T>(j);
262 write_((slot << V) | idx, word);
263 ++idx;
264 }
265 }
266
267 template <size_t V, typename A, typename T>
write_var(size_t slot,const Identifier * id,const Vector<Bits> & val)268 inline void VarTable<V,A,T>::write_var(size_t slot, const Identifier* id, const Vector<Bits>& val) {
269 const auto itr = vtable_.find(id);
270 assert(itr != vtable_.end());
271 assert(val.size() == itr->second.elements);
272
273 auto idx = itr->second.begin;
274 for (size_t i = 0; i < itr->second.elements; ++i) {
275 for (size_t j = 0; j < itr->second.words_per_element; ++j) {
276 const volatile auto word = val[i].read_word<T>(j);
277 write_((slot << V) | idx, word);
278 ++idx;
279 }
280 }
281 }
282
283 } // namespace cascade::avmm
284
285 #endif
286