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