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