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_REWRITE_H
32 #define CASCADE_SRC_TARGET_CORE_AVMM_REWRITE_H
33
34 #include <limits>
35 #include <map>
36 #include <set>
37 #include <sstream>
38 #include <string>
39 #include <vector>
40 #include "target/core/avmm/var_table.h"
41 #include "target/core/avmm/machinify.h"
42 #include "target/core/avmm/text_mangle.h"
43 #include "verilog/analyze/module_info.h"
44 #include "verilog/analyze/resolve.h"
45 #include "verilog/ast/visitors/visitor.h"
46 #include "verilog/ast/ast.h"
47 #include "verilog/build/ast_builder.h"
48 #include "verilog/print/print.h"
49 #include "verilog/transform/block_flatten.h"
50
51 namespace cascade::avmm {
52
53 template <size_t M, size_t V, typename A, typename T>
54 class Rewrite {
55 public:
56 std::string run(const ModuleDeclaration* md, size_t slot, const VarTable<V,A,T>* vt, const Identifier* clock);
57
58 private:
59 // Records variables which appear in timing control statements
60 struct TriggerIndex : Visitor {
61 TriggerIndex();
62 ~TriggerIndex() override = default;
63 std::map<std::string, const Identifier*> negedges_;
64 std::map<std::string, const Identifier*> posedges_;
65 void visit(const Event* e) override;
66 };
67
68 void emit_state_machine_vars(ModuleDeclaration* res, const Machinify<T>* mfy);
69 void emit_avalon_vars(ModuleDeclaration* res);
70 void emit_var_table(ModuleDeclaration* res, const VarTable<V,A,T>* vt);
71 void emit_shadow_vars(ModuleDeclaration* res, const ModuleDeclaration* md, const VarTable<V,A,T>* vt);
72 void emit_view_vars(ModuleDeclaration* res, const ModuleDeclaration* md, const VarTable<V,A,T>* vt);
73 void emit_update_vars(ModuleDeclaration* res, const VarTable<V,A,T>* vt);
74 void emit_state_vars(ModuleDeclaration* res);
75 void emit_trigger_vars(ModuleDeclaration* res, const TriggerIndex* ti);
76 void emit_open_loop_vars(ModuleDeclaration* res);
77
78 void emit_avalon_logic(ModuleDeclaration* res);
79 void emit_update_logic(ModuleDeclaration* res, const VarTable<V,A,T>* vt);
80 void emit_state_logic(ModuleDeclaration* res, const VarTable<V,A,T>* vt, const Machinify<T>* mfy);
81 void emit_trigger_logic(ModuleDeclaration* res, const TriggerIndex* ti);
82 void emit_open_loop_logic(ModuleDeclaration* res, const VarTable<V,A,T>* vt);
83 void emit_var_logic(ModuleDeclaration* res, const ModuleDeclaration* md, const VarTable<V,A,T>* vt, const Machinify<T>* mfy, const Identifier* open_loop_clock);
84 void emit_output_logic(ModuleDeclaration* res, const ModuleDeclaration* md, const VarTable<V,A,T>* vt);
85
86 void emit_subscript(Identifier* id, size_t idx, size_t n, const std::vector<size_t>& arity) const;
87 void emit_slice(Identifier* id, size_t w, size_t i) const;
88 };
89
90 template <size_t M, size_t V, typename A, typename T>
run(const ModuleDeclaration * md,size_t slot,const VarTable<V,A,T> * vt,const Identifier * clock)91 inline std::string Rewrite<M,V,A,T>::run(const ModuleDeclaration* md, size_t slot, const VarTable<V,A,T>* vt, const Identifier* clock) {
92 std::stringstream ss;
93
94 // Generate index tables before doing anything even remotely invasive
95 TriggerIndex ti;
96 md->accept(&ti);
97
98 // Emit a new declaration, with module name based on slot id. This
99 // declaration will use the Avalon Memory-mapped slave interface.
100 DeclBuilder db;
101 db << "module M" << static_cast<int>(slot) << "(__clk, __read, __write, __vid, __in, __out, __wait);" << std::endl;
102 db << "input wire __clk;" << std::endl;
103 db << "input wire __read;" << std::endl;
104 db << "input wire __write;" << std::endl;
105 db << "input wire[" << (M+V-1) << ":0] __vid;" << std::endl;
106 db << "input wire[" << (std::numeric_limits<T>::digits-1) << ":0] __in;" << std::endl;
107 db << "output reg[" << (std::numeric_limits<T>::digits-1) << ":0] __out;" << std::endl;
108 db << "output wire __wait;" << std::endl;
109 db << "endmodule" << std::endl;
110 auto *res = db.get();
111
112 emit_avalon_vars(res);
113 emit_var_table(res, vt);
114 emit_shadow_vars(res, md, vt);
115 emit_view_vars(res, md, vt);
116 emit_update_vars(res, vt);
117 emit_state_vars(res);
118 emit_trigger_vars(res, &ti);
119 emit_open_loop_vars(res);
120
121 // Emit original program logic
122 TextMangle<V,A,T> tm(md, vt);
123 md->accept_items(&tm, res->back_inserter_items());
124 Machinify<T> mfy;
125 mfy.run(res);
126
127 emit_state_machine_vars(res, &mfy);
128 emit_avalon_logic(res);
129 emit_update_logic(res, vt);
130 emit_state_logic(res, vt, &mfy);
131 emit_trigger_logic(res, &ti);
132 emit_open_loop_logic(res, vt);
133 emit_var_logic(res, md, vt, &mfy, clock);
134 emit_output_logic(res, md, vt);
135
136 // Final cleanup passes
137 BlockFlatten().run(res);
138
139 // Holy cow! We're done!
140 ss.str(std::string());
141 ss << res;
142 delete res;
143 return ss.str();
144 }
145
146 template <size_t M, size_t V, typename A, typename T>
TriggerIndex()147 inline Rewrite<M,V,A,T>::TriggerIndex::TriggerIndex() : Visitor() { }
148
149 template <size_t M, size_t V, typename A, typename T>
visit(const Event * e)150 inline void Rewrite<M,V,A,T>::TriggerIndex::visit(const Event* e) {
151 assert(e->get_expr()->is(Node::Tag::identifier));
152 const auto* i = static_cast<const Identifier*>(e->get_expr());
153 const auto* r = Resolve().get_resolution(i);
154 assert(r != nullptr);
155
156 switch (e->get_type()) {
157 case Event::Type::NEGEDGE:
158 negedges_[r->front_ids()->get_readable_sid()] = r;
159 break;
160 case Event::Type::POSEDGE:
161 posedges_[r->front_ids()->get_readable_sid()] = r;
162 break;
163 default:
164 // Don't record untyped edges
165 break;
166 }
167 }
168
169 template <size_t M, size_t V, typename A, typename T>
emit_state_machine_vars(ModuleDeclaration * res,const Machinify<T> * mfy)170 inline void Rewrite<M,V,A,T>::emit_state_machine_vars(ModuleDeclaration* res, const Machinify<T>* mfy) {
171 ItemBuilder ib;
172 ib << "reg[" << (std::numeric_limits<T>::digits-1) << ":0] __task_id[" << (mfy->end()-mfy->begin()-1) << ":0];" << std::endl;
173 ib << "reg[" << (std::numeric_limits<T>::digits-1) << ":0] __state[" << (mfy->end()-mfy->begin()-1) << ":0];" << std::endl;
174
175 res->push_back_items(ib.begin(), ib.end());
176 }
177
178 template <size_t M, size_t V, typename A, typename T>
emit_avalon_vars(ModuleDeclaration * res)179 inline void Rewrite<M,V,A,T>::emit_avalon_vars(ModuleDeclaration* res) {
180 ItemBuilder ib;
181 ib << "reg __read_prev = 0;" << std::endl;
182 ib << "wire __read_request;" << std::endl;
183 ib << "reg __write_prev = 0;" << std::endl;
184 ib << "wire __write_request;" << std::endl;
185 res->push_back_items(ib.begin(), ib.end());
186 }
187
188 template <size_t M, size_t V, typename A, typename T>
emit_var_table(ModuleDeclaration * res,const VarTable<V,A,T> * vt)189 inline void Rewrite<M,V,A,T>::emit_var_table(ModuleDeclaration* res, const VarTable<V,A,T>* vt) {
190 ItemBuilder ib;
191
192 // Emit the var table and the eof table
193 const auto var_arity = std::max(static_cast<size_t>(16), vt->size());
194 ib << "reg[" << (std::numeric_limits<T>::digits-1) << ":0] __var[" << (var_arity-1) << ":0];" << std::endl;
195 ib << "reg __feof[127:0];" << std::endl;
196
197 res->push_back_items(ib.begin(), ib.end());
198 }
199
200 template <size_t M, size_t V, typename A, typename T>
emit_shadow_vars(ModuleDeclaration * res,const ModuleDeclaration * md,const VarTable<V,A,T> * vt)201 inline void Rewrite<M,V,A,T>::emit_shadow_vars(ModuleDeclaration* res, const ModuleDeclaration* md, const VarTable<V,A,T>* vt) {
202 ModuleInfo info(md);
203
204 // Index the stateful elements in the variable table
205 std::map<std::string, typename VarTable<V,A,T>::const_iterator> vars;
206 for (auto v = vt->begin(), ve = vt->end(); v != ve; ++v) {
207 if (info.is_stateful(v->first)) {
208 vars.insert(make_pair(v->first->front_ids()->get_readable_sid(), v));
209 }
210 }
211
212 // Emit a shadow variable for every element with name suffixed by _next.
213 ItemBuilder ib;
214 for (const auto& v : vars) {
215 const auto itr = v.second;
216 assert(itr->first->get_parent() != nullptr);
217 assert(itr->first->get_parent()->is(Node::Tag::reg_declaration));
218
219 auto* rd = static_cast<const RegDeclaration*>(itr->first->get_parent())->clone();
220 rd->get_id()->purge_ids();
221 rd->get_id()->push_front_ids(new Id(v.first + "_next"));
222 rd->replace_val(nullptr);
223 ib << rd << std::endl;
224 delete rd;
225 }
226
227 // Emit update masks for the var table
228 const auto update_arity = std::max(static_cast<size_t>(32), vt->size());
229 ib << "reg[" << (update_arity-1) << ":0] __prev_update_mask = 0;" << std::endl;
230 ib << "reg[" << (update_arity-1) << ":0] __update_mask = 0;" << std::endl;
231
232 res->push_back_items(ib.begin(), ib.end());
233 }
234
235 template <size_t M, size_t V, typename A, typename T>
emit_view_vars(ModuleDeclaration * res,const ModuleDeclaration * md,const VarTable<V,A,T> * vt)236 inline void Rewrite<M,V,A,T>::emit_view_vars(ModuleDeclaration* res, const ModuleDeclaration* md, const VarTable<V,A,T>* vt) {
237 ModuleInfo info(md);
238
239 // Index both inputs and the stateful elements in the variable table
240 std::map<std::string, typename VarTable<V,A,T>::const_iterator> vars;
241 for (auto v = vt->begin(), ve = vt->end(); v != ve; ++v) {
242 if (info.is_input(v->first) || info.is_stateful(v->first)) {
243 vars.insert(make_pair(v->first->front_ids()->get_readable_sid(), v));
244 }
245 }
246
247 // Emit views for these variables
248 ItemBuilder ib;
249 for (const auto& v : vars) {
250 const auto itr = v.second;
251 assert(itr->first->get_parent() != nullptr);
252 assert(itr->first->get_parent()->is_subclass_of(Node::Tag::declaration));
253 const auto* d = static_cast<const Declaration*>(itr->first->get_parent());
254
255 auto* nd = new NetDeclaration(
256 new Attributes(),
257 d->get_id()->clone(),
258 d->get_type(),
259 d->is_non_null_dim() ? d->clone_dim() : nullptr
260 );
261 ib << nd << std::endl;
262 delete nd;
263
264 for (size_t i = 0, ie = itr->second.elements; i < ie; ++i) {
265 auto* lhs = itr->first->clone();
266 lhs->purge_dim();
267 emit_subscript(lhs, i, ie, Evaluate().get_arity(itr->first));
268 ib << "assign " << lhs << " = {";
269 delete lhs;
270
271 for (size_t j = 0, je = itr->second.words_per_element; j < je; ) {
272 ib << "__var[" << (itr->second.begin + (i+1)*je-j-1) << "]";
273 if (++j != je) {
274 ib << ",";
275 }
276 }
277 ib << "};" << std::endl;
278 }
279 }
280
281 res->push_back_items(ib.begin(), ib.end());
282 }
283
284 template <size_t M, size_t V, typename A, typename T>
emit_update_vars(ModuleDeclaration * res,const VarTable<V,A,T> * vt)285 inline void Rewrite<M,V,A,T>::emit_update_vars(ModuleDeclaration* res, const VarTable<V,A,T>* vt) {
286 ItemBuilder ib;
287
288 const auto update_arity = std::max(static_cast<size_t>(32), vt->size());
289 ib << "wire[" << (update_arity-1) << ":0] __update_queue;" << std::endl;
290 ib << "wire __there_are_updates;" << std::endl;
291 ib << "wire __apply_updates;" << std::endl;
292
293 res->push_back_items(ib.begin(), ib.end());
294 }
295
296 template <size_t M, size_t V, typename A, typename T>
emit_state_vars(ModuleDeclaration * res)297 inline void Rewrite<M,V,A,T>::emit_state_vars(ModuleDeclaration* res) {
298 ItemBuilder ib;
299
300 ib << "wire __there_were_tasks;" << std::endl;
301 ib << "wire __all_final;" << std::endl;
302 ib << "wire __continue;" << std::endl;
303 ib << "wire __reset;" << std::endl;
304
305 res->push_back_items(ib.begin(), ib.end());
306 }
307
308 template <size_t M, size_t V, typename A, typename T>
emit_trigger_vars(ModuleDeclaration * res,const TriggerIndex * ti)309 inline void Rewrite<M,V,A,T>::emit_trigger_vars(ModuleDeclaration* res, const TriggerIndex* ti) {
310 ItemBuilder ib;
311
312 // Index triggers
313 std::map<std::string, const Identifier*> vars;
314 for (auto& e : ti->negedges_) {
315 vars[e.first] = e.second;
316 }
317 for (auto& e : ti->posedges_) {
318 vars[e.first] = e.second;
319 }
320
321 // Emit variables for storing previous values of trigger variables
322 for (const auto& v : vars) {
323 assert(v.second->get_parent() != nullptr);
324 assert(v.second->get_parent()->is_subclass_of(Node::Tag::declaration));
325 const auto* d = static_cast<const Declaration*>(v.second->get_parent());
326
327 auto* rd = new RegDeclaration(
328 new Attributes(),
329 new Identifier(v.first + "_prev"),
330 d->get_type(),
331 d->is_non_null_dim() ? d->clone_dim() : nullptr,
332 nullptr
333 );
334 ib << rd << std::endl;
335 delete rd;
336 }
337
338 // Emit edge variables (these should be sorted determinstically by virtue of
339 // how these sets were built)
340 for (const auto& e : ti->negedges_) {
341 ib << "wire " << e.first << "_negedge;" << std::endl;
342 }
343 for (auto& e : ti->posedges_) {
344 ib << "wire " << e.first << "_posedge;" << std::endl;
345 }
346
347 // Emit var for tracking whether any triggers just occurred
348 ib << "wire __any_triggers;" << std::endl;
349
350 res->push_back_items(ib.begin(), ib.end());
351 }
352
353 template <size_t M, size_t V, typename A, typename T>
emit_open_loop_vars(ModuleDeclaration * res)354 inline void Rewrite<M,V,A,T>::emit_open_loop_vars(ModuleDeclaration* res) {
355 ItemBuilder ib;
356
357 ib << "reg[" << (std::numeric_limits<T>::digits-1) << ":0] __open_loop = 0;" << std::endl;
358 ib << "wire __open_loop_tick;" << std::endl;
359
360 res->push_back_items(ib.begin(), ib.end());
361 }
362
363 template <size_t M, size_t V, typename A, typename T>
emit_avalon_logic(ModuleDeclaration * res)364 inline void Rewrite<M,V,A,T>::emit_avalon_logic(ModuleDeclaration* res) {
365 ItemBuilder ib;
366 ib << "always @(posedge __clk) __read_prev <= __read;" << std::endl;
367 ib << "assign __read_request = (!__read_prev && __read);" << std::endl;
368 ib << "always @(posedge __clk) __write_prev <= __write;" << std::endl;
369 ib << "assign __write_request = (!__write_prev && __write);" << std::endl;
370 res->push_back_items(ib.begin(), ib.end());
371 }
372
373 template <size_t M, size_t V, typename A, typename T>
emit_update_logic(ModuleDeclaration * res,const VarTable<V,A,T> * vt)374 inline void Rewrite<M,V,A,T>::emit_update_logic(ModuleDeclaration* res, const VarTable<V,A,T>* vt) {
375 ItemBuilder ib;
376
377 const auto update_arity = std::max(static_cast<size_t>(32), vt->size());
378 ib << "assign __update_queue = (__prev_update_mask ^ __update_mask);" << std::endl;
379 ib << "assign __there_are_updates = |__update_queue;" << std::endl;
380 ib << "assign __apply_updates = ((__read_request && (__vid == " << vt->apply_update_index() << ")) || (__there_are_updates && __open_loop_tick));" << std::endl;
381 ib << "always @(posedge __clk) __prev_update_mask <= ((__apply_updates || __reset) ? __update_mask : __prev_update_mask);" << std::endl;
382
383 res->push_back_items(ib.begin(), ib.end());
384 }
385
386 template <size_t M, size_t V, typename A, typename T>
emit_state_logic(ModuleDeclaration * res,const VarTable<V,A,T> * vt,const Machinify<T> * mfy)387 inline void Rewrite<M,V,A,T>::emit_state_logic(ModuleDeclaration* res, const VarTable<V,A,T>* vt, const Machinify<T>* mfy) {
388 ItemBuilder ib;
389
390 if (mfy->begin() == mfy->end()) {
391 ib << "assign __there_were_tasks = 0;" << std::endl;
392 ib << "assign __all_final = 1;" << std::endl;
393 } else {
394 ib << "assign __there_were_tasks = |{";
395 for (auto i = mfy->begin(), ie = mfy->end(); i != ie;) {
396 ib << "__task_id[" << i->name() << "] != 0";
397 if (++i != ie) {
398 ib << ",";
399 }
400 }
401 ib << "};" << std::endl;
402 ib << "assign __all_final = &{";
403 for (auto i = mfy->begin(), ie = mfy->end(); i != ie; ) {
404 ib << "__state[" << i->name() << "] == " << i->final_state();
405 if (++i != ie) {
406 ib << ",";
407 }
408 }
409 ib << "};" << std::endl;
410 }
411
412 ib << "assign __continue = ((__read_request && (__vid == " << vt->resume_index() << ")) || (!__all_final && !__there_were_tasks));" << std::endl;
413 ib << "assign __reset = (__read_request && (__vid == " << vt->reset_index() << "));" << std::endl;
414
415 res->push_back_items(ib.begin(), ib.end());
416 }
417
418 template <size_t M, size_t V, typename A, typename T>
emit_trigger_logic(ModuleDeclaration * res,const TriggerIndex * ti)419 inline void Rewrite<M,V,A,T>::emit_trigger_logic(ModuleDeclaration* res, const TriggerIndex* ti) {
420 ItemBuilder ib;
421
422 // Index trigger variables
423 std::set<std::string> vars;
424 for (const auto& e : ti->negedges_) {
425 vars.insert(e.first);
426 }
427 for (const auto& e : ti->posedges_) {
428 vars.insert(e.first);
429 }
430
431 // Emit updates for trigger variables
432 ib << "always @(posedge __clk) begin" << std::endl;
433 for (const auto& v : vars) {
434 ib << v << "_prev <= " << v << ";" << std::endl;
435 }
436 ib << "end" << std::endl;
437
438 // Emit edge variables (these should be sorted determinstically by virtue of
439 // how these sets were built)
440 for (const auto& e : ti->negedges_) {
441 ib << "assign " << e.first << "_negedge = (" << e.first << "_prev == 1) && (" << e.first << " == 0);" << std::endl;
442 }
443 for (auto& e : ti->posedges_) {
444 ib << "assign " << e.first << "_posedge = (" << e.first << "_prev == 0) && (" << e.first << " == 1);" << std::endl;
445 }
446
447 // Emit logic for tracking whether any triggers just occurred
448 if (ti->posedges_.empty() && ti->negedges_.empty()) {
449 ib << "assign __any_triggers = 0;" << std::endl;
450 } else {
451 ib << "assign __any_triggers = |{";
452 for (auto i = ti->negedges_.begin(), ie = ti->negedges_.end(); i != ie; ) {
453 ib << i->first << "_negedge";
454 if ((++i != ie) || !ti->posedges_.empty()) {
455 ib << ",";
456 }
457 }
458 for (auto i = ti->posedges_.begin(), ie = ti->posedges_.end(); i != ie; ) {
459 ib << i->first << "_posedge";
460 if (++i != ie) {
461 ib << ",";
462 }
463 }
464 ib << "};" << std::endl;
465 }
466
467 res->push_back_items(ib.begin(), ib.end());
468 }
469
470 template <size_t M, size_t V, typename A, typename T>
emit_open_loop_logic(ModuleDeclaration * res,const VarTable<V,A,T> * vt)471 inline void Rewrite<M,V,A,T>::emit_open_loop_logic(ModuleDeclaration* res, const VarTable<V,A,T>* vt) {
472 ItemBuilder ib;
473
474 ib << "always @(posedge __clk) __open_loop <= ((__read_request && (__vid == " << vt->open_loop_index() << ")) ? __in : (__open_loop_tick ? (__open_loop - 1) : __open_loop));" << std::endl;
475 ib << "assign __open_loop_tick = (__all_final && (!__any_triggers && (__open_loop > 0)));" << std::endl;
476
477 res->push_back_items(ib.begin(), ib.end());
478 }
479
480 template <size_t M, size_t V, typename A, typename T>
emit_var_logic(ModuleDeclaration * res,const ModuleDeclaration * md,const VarTable<V,A,T> * vt,const Machinify<T> * mfy,const Identifier * clock)481 inline void Rewrite<M,V,A,T>::emit_var_logic(ModuleDeclaration* res, const ModuleDeclaration* md, const VarTable<V,A,T>* vt, const Machinify<T>* mfy, const Identifier* clock) {
482 ModuleInfo info(md);
483
484 // Index both inputs and stateful elements in the variable table
485 std::map<size_t, typename VarTable<V,A,T>::const_iterator> vars;
486 for (auto t = vt->begin(), te = vt->end(); t != te; ++t) {
487 if (info.is_input(t->first) || info.is_stateful(t->first)) {
488 vars[t->second.begin] = t;
489 }
490 }
491
492 ItemBuilder ib;
493 ib << "always @(posedge __clk) begin" << std::endl;
494 for (auto i = mfy->begin(), ie = mfy->end(); i != ie; ++i) {
495 ib << i->text() << std::endl;
496 }
497 for (const auto& v : vars) {
498 const auto itr = v.second;
499 if ((clock != nullptr) && (itr->first == clock)) {
500 const auto idx = itr->second.begin;
501 ib << "if (__open_loop_tick)" << std::endl;
502 ib << "__var[" << idx << "] <= {" << (std::numeric_limits<T>::digits-1) << "'d0,~" << itr->first->front_ids()->get_readable_sid() << "};" << std::endl;
503 break;
504 }
505 }
506 ib << "if (__apply_updates && |__update_queue) begin" << std::endl;
507 for (const auto& v : vars) {
508 const auto itr = v.second;
509 const auto arity = Evaluate().get_arity(itr->first);
510 const auto w = itr->second.bits_per_element;
511 auto idx = itr->second.begin;
512 if ((clock != nullptr) && (itr->first == clock)) {
513 continue;
514 }
515 if (!info.is_stateful(itr->first)) {
516 continue;
517 }
518 for (size_t i = 0, ie = itr->second.elements; i < ie; ++i) {
519 for (size_t j = 0, je = itr->second.words_per_element; j < je; ++j) {
520 ib << "__var[" << idx << "] <= ";
521 auto* id = new Identifier(itr->first->front_ids()->get_readable_sid() + "_next");
522 emit_subscript(id, i, ie, arity);
523 emit_slice(id, w, j);
524 ib << "(__update_queue[" << idx << "]) ? " << id << " : ";
525 delete id;
526 ib << "__var[" << idx << "];" << std::endl;
527 ++idx;
528 }
529 }
530 }
531 ib << "end" << std::endl;
532 ib << "if (__read_request && (__vid < " << vt->there_are_updates_index() << "))" << std::endl;
533 ib << "__var[__vid] <= __in;" << std::endl;
534 ib << "end" << std::endl;
535
536 ib << "always @(posedge __clk) begin" << std::endl;
537 ib << "if (__read_request && (__vid == " << vt->feof_index() << "))" << std::endl;
538 ib << "__feof[__in >> 1] <= __in[0];" << std::endl;
539 ib << "end" << std::endl;
540
541 res->push_back_items(ib.begin(), ib.end());
542 }
543
544 template <size_t M, size_t V, typename A, typename T>
emit_output_logic(ModuleDeclaration * res,const ModuleDeclaration * md,const VarTable<V,A,T> * vt)545 inline void Rewrite<M,V,A,T>::emit_output_logic(ModuleDeclaration* res, const ModuleDeclaration* md, const VarTable<V,A,T>* vt) {
546 ModuleInfo info(md);
547
548 // Index the elements in the variable table which aren't inputs or stateful.
549 std::map<size_t, typename VarTable<V,A,T>::const_iterator> outputs;
550 for (auto t = vt->begin(), te = vt->end(); t != te; ++t) {
551 if (!info.is_input(t->first) && !info.is_stateful(t->first)) {
552 outputs[t->second.begin] = t;
553 }
554 }
555
556 ItemBuilder ib;
557 ib << "always @*" << std::endl;
558 ib << "case(__vid)" << std::endl;
559
560 for (const auto& o : outputs) {
561 const auto itr = o.second;
562 assert(itr->second.elements == 1);
563 const auto w = itr->second.bits_per_element;
564 for (size_t i = 0; i < itr->second.words_per_element; ++i) {
565 ib << (itr->second.begin+i) << ": __out = ";
566
567 auto* id = itr->first->clone();
568 id->purge_dim();
569 emit_slice(id, w, i);
570 ib << id << ";" << std::endl;
571
572 delete id;
573 }
574 }
575
576 ib << vt->there_are_updates_index() << ": __out = __there_are_updates;" << std::endl;
577 ib << vt->there_were_tasks_index() << ": __out = __task_id[0];" << std::endl;
578 ib << vt->open_loop_index() << ": __out = __open_loop;" << std::endl;
579 ib << vt->debug_index() << ": __out = __state[0];" << std::endl;
580 ib << "default: __out = __var[__vid];" << std::endl;
581 ib << "endcase" << std::endl;
582 ib << "assign __wait = __read_request || __write_request || __open_loop_tick || __any_triggers || __continue;" << std::endl;
583
584 res->push_back_items(ib.begin(), ib.end());
585 }
586
587 template <size_t M, size_t V, typename A, typename T>
emit_subscript(Identifier * id,size_t idx,size_t n,const std::vector<size_t> & arity)588 inline void Rewrite<M,V,A,T>::emit_subscript(Identifier* id, size_t idx, size_t n, const std::vector<size_t>& arity) const {
589 for (auto a : arity) {
590 n /= a;
591 const auto i = idx / n;
592 idx -= i*n;
593 id->push_back_dim(new Number(Bits(std::numeric_limits<T>::digits, i)));
594 }
595 }
596
597 template <size_t M, size_t V, typename A, typename T>
emit_slice(Identifier * id,size_t w,size_t i)598 inline void Rewrite<M,V,A,T>::emit_slice(Identifier* id, size_t w, size_t i) const {
599 const auto upper = std::min(std::numeric_limits<T>::digits*(i+1),w);
600 const auto lower = std::numeric_limits<T>::digits*i;
601 if (upper == 1) {
602 // Do nothing
603 } else if (upper > lower) {
604 id->push_back_dim(new RangeExpression(upper, lower));
605 } else {
606 id->push_back_dim(new Number(Bits(std::numeric_limits<T>::digits, lower)));
607 }
608 }
609
610 } // namespace cascade::avmm
611
612 #endif
613