PandA-2024.02
BuiltinWaitCallNModuleGenerator.cpp
Go to the documentation of this file.
1 /*
2  *
3  * _/_/_/ _/_/ _/ _/ _/_/_/ _/_/
4  * _/ _/ _/ _/ _/_/ _/ _/ _/ _/ _/
5  * _/_/_/ _/_/_/_/ _/ _/_/ _/ _/ _/_/_/_/
6  * _/ _/ _/ _/ _/ _/ _/ _/ _/
7  * _/ _/ _/ _/ _/ _/_/_/ _/ _/
8  *
9  * ***********************************************
10  * PandA Project
11  * URL: http://panda.dei.polimi.it
12  * Politecnico di Milano - DEIB
13  * System Architectures Group
14  * ***********************************************
15  * Copyright (C) 2022-2024 Politecnico di Milano
16  *
17  * This file is part of the PandA framework.
18  *
19  * The PandA framework is free software; you can redistribute it and/or modify
20  * it under the terms of the GNU General Public License as published by
21  * the Free Software Foundation; either version 3 of the License, or
22  * (at your option) any later version.
23  *
24  * This program is distributed in the hope that it will be useful,
25  * but WITHOUT ANY WARRANTY; without even the implied warranty of
26  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27  * GNU General Public License for more details.
28  *
29  * You should have received a copy of the GNU General Public License
30  * along with this program. If not, see <http://www.gnu.org/licenses/>.
31  *
32  */
49 
50 #include "application_manager.hpp"
51 #include "function_behavior.hpp"
52 #include "hls_manager.hpp"
53 #include "language_writer.hpp"
54 #include "math_function.hpp"
55 #include "op_graph.hpp"
56 #include "structural_objects.hpp"
57 #include "tree_helper.hpp"
58 #include "tree_manager.hpp"
59 #include "tree_reindex.hpp"
60 
62 {
63 }
64 
66  unsigned int function_id, vertex op_v,
67  const HDLWriter_Language /* language */,
68  const std::vector<ModuleGenerator::parameter>& _p,
69  const std::vector<ModuleGenerator::parameter>& /* _ports_in */,
70  const std::vector<ModuleGenerator::parameter>& /* _ports_out */,
71  const std::vector<ModuleGenerator::parameter>& /* _ports_inout */)
72 {
73  const auto retval_size = [&]() {
74  THROW_ASSERT(function_id && op_v, "");
75  const auto FB = HLSMgr->CGetFunctionBehavior(function_id);
76  const auto TM = HLSMgr->get_tree_manager();
77  const auto call_stmt =
78  TM->CGetTreeNode(FB->CGetOpGraph(FunctionBehavior::CFG)->CGetOpNodeInfo(op_v)->GetNodeId());
79  THROW_ASSERT(call_stmt && call_stmt->get_kind() == gimple_call_K, "Expected gimple call statement.");
80  const auto gc = GetPointerS<const gimple_call>(call_stmt);
81  THROW_ASSERT(gc->args.size() >= 2, "Expected at least two arguments for the builtin wait call.");
82  const auto called_addr = gc->args.at(0);
83  const auto called_hasreturn = gc->args.at(1);
84  THROW_ASSERT(GET_CONST_NODE(called_hasreturn)->get_kind() == integer_cst_K, "");
85  if(tree_helper::GetConstValue(called_hasreturn))
86  {
87  const auto fpointer_type = tree_helper::CGetType(called_addr);
88  const auto called_ftype = tree_helper::CGetPointedType(fpointer_type);
89  const auto return_type = tree_helper::GetFunctionReturnType(called_ftype);
90  if(return_type)
91  {
92  return tree_helper::Size(return_type);
93  }
94  }
95  return 0ULL;
96  }();
97 
98  // Signals declarations
99  if(_p.size() == 3U)
100  {
101  out << "reg [0:0] index;\n\n";
102  }
103  else if(_p.size() > 3U)
104  {
105  out << "reg [" << ceil_log2(_p.size() - 2U) << "-1:0] index;\n\n";
106  }
107 
108  if(_p.size() > 2U)
109  {
110  out << "wire [BITSIZE_Mout_addr_ram-1:0] paramAddressRead;\n\n";
111  }
112 
113  out << "reg [31:0] step;\n"
114  << "reg [31:0] next_step;\n"
115  << "reg done_port;\n"
116  << "reg [PORTSIZE_Sout_DataRdy-1:0] Sout_DataRdy;\n"
117  << "reg [PORTSIZE_Mout_oe_ram-1:0] Mout_oe_ram;\n"
118  << "reg [PORTSIZE_Mout_we_ram-1:0] Mout_we_ram;\n"
119  << "reg [PORTSIZE_Mout_addr_ram*BITSIZE_Mout_addr_ram-1:0] Mout_addr_ram;\n"
120  << "reg [PORTSIZE_Mout_Wdata_ram*BITSIZE_Mout_Wdata_ram-1:0] Mout_Wdata_ram;\n"
121  << "reg [PORTSIZE_Mout_data_ram_size*BITSIZE_Mout_data_ram_size-1:0] Mout_data_ram_size;\n"
122  << "reg active_request;\n"
123  << "reg active_request_next;\n\n";
124 
125  if(retval_size)
126  {
127  out << "reg [" << retval_size << "-1:0] readValue 1INIT_ZERO_VALUE;\n"
128  << "reg [" << retval_size << "-1:0] next_readValue;\n\n";
129  }
130 
131  if(_p.size() > 2U)
132  {
133  out << "reg [BITSIZE_Mout_addr_ram-1:0] paramAddress [" << (_p.size() - 2U) << "-1:0];\n\n";
134  }
135 
136  out << "function [PORTSIZE_S_addr_ram-1:0] check_condition;\n"
137  << " input [PORTSIZE_S_addr_ram*BITSIZE_S_addr_ram-1:0] m;\n"
138  << " integer i1;\n"
139  << " begin\n"
140  << " for(i1 = 0; i1 < PORTSIZE_S_addr_ram; i1 = i1 + 1)\n"
141  << " begin\n"
142  << " check_condition[i1] = m[i1*BITSIZE_S_addr_ram +:BITSIZE_S_addr_ram] == unlock_address;\n"
143  << " end\n"
144  << " end\n"
145  << "endfunction\n";
146 
147  out << "wire [PORTSIZE_S_addr_ram-1:0] internal;\n";
148 
149  out << "parameter [31:0] ";
150  const auto n_iterations = retval_size ? (_p.size() + 3U) : _p.size();
151  for(auto idx = 0U; idx <= n_iterations; ++idx)
152  {
153  if(idx != n_iterations)
154  {
155  out << "S_" << idx << " = 32'd" << idx << ",\n";
156  }
157  else
158  {
159  out << "S_" << idx << " = 32'd" << idx << ";\n";
160  }
161  }
162 
163  if(_p.size() > 2U)
164  {
165  out << "initial\n"
166  << " begin\n"
167  << " $readmemb(MEMORY_INIT_file, paramAddress, 0, " << (_p.size() - 2U) << "-1);\n"
168  << " end\n\n\n";
169  }
170 
171  if(_p.size() > 2U)
172  {
173  out << "assign paramAddressRead = paramAddress[index];\n";
174  }
175  out << "assign Sout_Rdata_ram = Sin_Rdata_ram;\n"
176  << "assign internal = check_condition(S_addr_ram);\n";
177 
178  // State machine
179  out << "always @ (posedge clock 1RESET_EDGE)\n"
180  << " if (1RESET_VALUE)\n"
181  << " begin\n"
182  << " step <= 0;\n";
183 
184  if(retval_size)
185  {
186  if(retval_size == 1U)
187  {
188  out << " readValue <= {1'b0};\n";
189  }
190  else
191  {
192  out << " readValue <= {" << retval_size << " {1'b0}};\n";
193  }
194  out << " end else begin\n"
195  << " step <= next_step;\n"
196  << " readValue <= next_readValue;\n"
197  << " end\n\n";
198  }
199  else
200  {
201  out << " end else begin\n"
202  << " step <= next_step;\n"
203  << " end\n\n";
204  }
205 
206  if(_p.size() > 2U)
207  {
208  out << "always @(*)\n"
209  << " begin\n"
210  << " index = 0;\n"
211  << " if (step == S_0) begin\n"
212  << " index = 0;\n"
213  << " end\n";
214  }
215 
216  auto idx = 1U;
217  if(_p.size() > 3)
218  {
219  for(idx = 1U; idx <= (_p.size() - 3U); ++idx)
220  {
221  out << " else if (step == S_" << idx << ") begin\n"
222  << " index = " << (idx - 1U) << ";\n"
223  << " end\n";
224  }
225  }
226  if(_p.size() > 2U)
227  {
228  out << " else if (step == S_" << idx << ") begin\n"
229  << " index = " << (idx - 1U) << ";\n"
230  << " end\n";
231  idx++;
232  }
233 
234  idx++;
235 
236  idx++;
237 
238  if(_p.size() > 2U && retval_size)
239  {
240  out << " else if (step == S_" << idx << ") begin\n"
241  << " index = " << (idx - 4U) << ";\n"
242  << " end\n";
243  idx++;
244  }
245  if(_p.size() > 2U)
246  {
247  out << "end\n";
248  }
249 
250  out << "always @ (posedge clock 1RESET_EDGE)\n"
251  << " if (1RESET_VALUE)\n"
252  << " begin\n"
253  << " active_request <= 0;\n"
254  << " end\n"
255  << " else\n"
256  << " begin\n"
257  << " active_request <= active_request_next;\n"
258  << " end\n\n";
259 
260  out << "always @(*)\n"
261  << " begin\n"
262  << " Sout_DataRdy = Sin_DataRdy;\n"
263  << " done_port = 1'b0;\n"
264  << " next_step = S_0;\n"
265  << (retval_size ? " next_readValue = readValue;\n" : "") << " Mout_we_ram = Min_we_ram;\n"
266  << " Mout_Wdata_ram = Min_Wdata_ram;\n"
267  << " Mout_oe_ram = Min_oe_ram;\n"
268  << " Mout_addr_ram = Min_addr_ram;\n"
269  << " Mout_data_ram_size = Min_data_ram_size;\n"
270  << " active_request_next = 0;\n";
271 
272  out << " if (step == S_0) begin\n"
273  << " if (start_port == 1'b1) begin\n"
274  << " active_request_next = 1;\n";
275  if(_p.size() == 3U)
276  {
277  out << " next_step = in2[0] ? S_2 : S_1;\n";
278  }
279  else
280  {
281  out << " next_step = S_1;\n";
282  }
283  out << " end else begin\n"
284  << " next_step = S_0;\n"
285  << " end\n"
286  << " end\n";
287  idx = 1U;
288  if(_p.size() > 3)
289  {
290  for(idx = 1U; idx <= (_p.size() - 3U); ++idx)
291  {
292  if(idx != (_p.size() - 3U))
293  {
294  out << " else if (step == S_" << idx << ") begin\n"
295  << " Mout_we_ram[0] = active_request;\n"
296  << " Mout_addr_ram[BITSIZE_Mout_addr_ram-1:0] = (in1 + paramAddressRead) & "
297  "{BITSIZE_Mout_addr_ram{active_request}};\n"
298  << " Mout_Wdata_ram[BITSIZE_Mout_Wdata_ram-1:0] = " << _p[idx + 1].name
299  << " & {BITSIZE_Mout_Wdata_ram{active_request}};\n"
300  << " Mout_data_ram_size[BITSIZE_Mout_data_ram_size-1:0] = " << _p[idx + 1].type_size
301  << " & {BITSIZE_Mout_data_ram_size{active_request}};\n"
302  << " if (M_DataRdy[0] == 1'b1) begin\n"
303  << " next_step = S_" << (idx + 1U) << ";\n"
304  << " active_request_next = 1;\n"
305  << " end else begin\n"
306  << " next_step = S_" << idx << ";\n"
307  << " end\n"
308  << " end\n";
309  }
310  else
311  {
312  out << " else if (step == S_" << idx << ") begin\n"
313  << " Mout_we_ram[0] = active_request;\n"
314  << " Mout_addr_ram[BITSIZE_Mout_addr_ram-1:0] = (in1 + paramAddressRead) & "
315  "{BITSIZE_Mout_addr_ram{active_request}};\n"
316  << " Mout_Wdata_ram[BITSIZE_Mout_Wdata_ram-1:0] = " << _p[idx + 1].name
317  << " & {BITSIZE_Mout_Wdata_ram{active_request}};\n"
318  << " Mout_data_ram_size[BITSIZE_Mout_data_ram_size-1:0] = " << _p[idx + 1].type_size
319  << " & {BITSIZE_Mout_data_ram_size{active_request}};\n"
320  << " if (M_DataRdy[0] == 1'b1) begin\n"
321  << " next_step = in2[0] ? S_" << (idx + 2U) << " : S_" << (idx + 1U) << ";\n"
322  << " active_request_next = 1;\n"
323  << " end else begin\n"
324  << " next_step = S_" << idx << ";\n"
325  << " end\n"
326  << " end\n";
327  }
328  }
329  }
330  if(_p.size() > 2U)
331  {
332  out << " else if (step == S_" << idx << ") begin\n"
333  << " Mout_we_ram[0] = active_request;\n"
334  << " Mout_addr_ram[BITSIZE_Mout_addr_ram-1:0] = (in1 + paramAddressRead) & "
335  "{BITSIZE_Mout_addr_ram{active_request}};\n"
336  << " Mout_Wdata_ram[BITSIZE_Mout_Wdata_ram-1:0] = " << _p[idx + 1].name
337  << " & {BITSIZE_Mout_Wdata_ram{active_request}};\n"
338  << " Mout_data_ram_size[BITSIZE_Mout_data_ram_size-1:0] = " << _p[idx + 1].type_size
339  << " & {BITSIZE_Mout_data_ram_size{active_request}};\n"
340  << " if (M_DataRdy[0] == 1'b1) begin\n"
341  << " next_step = S_" << (idx + 1U) << ";\n"
342  << " active_request_next = 1;\n"
343  << " end else begin\n"
344  << " next_step = S_" << idx << ";\n"
345  << " end\n"
346  << " end\n";
347  idx++;
348  }
349 
350  out << " else if (step == S_" << idx << ") begin\n"
351  << " Mout_we_ram[0] = active_request;\n"
352  << " Mout_addr_ram[BITSIZE_Mout_addr_ram-1:0] = in1 & {BITSIZE_Mout_addr_ram{active_request}};\n"
353  << " Mout_Wdata_ram[BITSIZE_Mout_Wdata_ram-1:0] = unlock_address & "
354  "{BITSIZE_Mout_Wdata_ram{active_request}};\n"
355  << " Mout_data_ram_size[BITSIZE_Mout_data_ram_size-1:0] = BITSIZE_Mout_Wdata_ram & "
356  "{BITSIZE_Mout_data_ram_size{active_request}};\n"
357  << " if (M_DataRdy[0] == 1'b1) begin\n"
358  << " next_step = S_" << (idx + 1U) << ";\n"
359  << " active_request_next = 1;\n"
360  << " end else begin\n"
361  << " next_step = S_" << idx << ";\n"
362  << " end"
363  << " end\n";
364  idx++;
365 
366  out << " else if (step == S_" << idx << ") begin\n"
367  << " if (|(S_we_ram & internal)) begin\n"
368  << " Sout_DataRdy = (S_we_ram & internal) | Sin_DataRdy;\n"
369  << " next_step = in2[0] ? S_" << (retval_size ? (idx + 1U) : 0U) << " : S_0;\n"
370  << " active_request_next = 1;\n"
371  << " done_port = in2[0] ? 1'b0 : 1'b1;\n"
372  << " end else begin\n"
373  << " next_step = S_" << idx << ";\n"
374  << " end\n"
375  << " end\n";
376  idx++;
377 
378  if(_p.size() > 2U && retval_size)
379  {
380  out << " else if (step == S_" << idx << ") begin\n"
381  << " Mout_oe_ram[0] = active_request;\n"
382  << " Mout_addr_ram[BITSIZE_Mout_addr_ram-1:0] = (in1 + paramAddressRead) & "
383  "{BITSIZE_Mout_addr_ram{active_request}};\n"
384  << " Mout_data_ram_size[BITSIZE_Mout_data_ram_size-1:0] = " << retval_size
385  << " & {BITSIZE_Mout_data_ram_size{active_request}};\n"
386  << " if (M_DataRdy[0] == 1'b1) begin\n"
387  << " next_step = S_" << (idx + 1U) << ";\n"
388  << " active_request_next = 1;\n"
389  << " next_readValue = M_Rdata_ram;\n"
390  << " end else begin\n"
391  << " next_step = S_" << idx << ";\n"
392  << " end"
393  << " end\n";
394  idx++;
395 
396  out << " else if (step == S_" << idx << ") begin\n"
397  << " Mout_we_ram[0] = active_request;\n"
398  << " Mout_addr_ram[BITSIZE_Mout_addr_ram-1:0] = " << _p[_p.size() - 1U].name
399  << " & {BITSIZE_Mout_addr_ram{active_request}};\n"
400  << " Mout_Wdata_ram[BITSIZE_Mout_Wdata_ram-1:0] = readValue & {BITSIZE_Mout_Wdata_ram{active_request}};\n"
401  << " Mout_data_ram_size[BITSIZE_Mout_data_ram_size-1:0] = " << retval_size
402  << " & {BITSIZE_Mout_data_ram_size{active_request}};\n"
403  << " if (M_DataRdy[0] == 1'b1) begin\n"
404  << " next_step = S_0;\n"
405  << " active_request_next = 1;\n"
406  << " done_port = 1'b1;\n"
407  << " end else begin\n"
408  << " next_step = S_" << idx << ";\n"
409  << " end"
410  << " end\n";
411  }
412  out << "end\n";
413 }
Data structure representing the entire HLS information.
Definition of the class representing a generic C application.
mathematical utility function not provided by standard libraries
HDLWriter_Language
T ceil_log2(T x)
Return the smallest n such that 2**n >= X.
static unsigned long long Size(const tree_nodeConstRef &tn)
Return the size of a tree object.
Control flow graph.
This class writes different HDL based descriptions (VHDL, Verilog, SystemC) starting from a structura...
boost::graph_traits< graph >::vertex_descriptor vertex
vertex definition.
Definition: graph.hpp:1303
#define GET_CONST_NODE(t)
Definition: tree_node.hpp:347
This file collects some utility functions.
This class describes all classes used to represent a structural object.
void InternalExec(std::ostream &out, structural_objectRef mod, unsigned int function_id, vertex op_v, const HDLWriter_Language language, const std::vector< ModuleGenerator::parameter > &_p, const std::vector< ModuleGenerator::parameter > &_ports_in, const std::vector< ModuleGenerator::parameter > &_ports_out, const std::vector< ModuleGenerator::parameter > &_ports_inout) final
Class specification of the tree_reindex support class.
Data structures used in operations graph.
Template borrowed from the ANTLR library by Terence Parr (http://www.jGuru.com - Software rights: htt...
Definition: refcount.hpp:94
static tree_nodeConstRef CGetType(const tree_nodeConstRef &node)
Return the treenode of the type of node.
BuiltinWaitCallNModuleGenerator(const HLS_managerRef &HLSMgr)
static tree_nodeConstRef CGetPointedType(const tree_nodeConstRef &pointer)
Return the pointed type of a pointer object.
static integer_cst_t GetConstValue(const tree_nodeConstRef &tn, bool is_signed=true)
Get value from integer constant.
static tree_nodeConstRef GetFunctionReturnType(const tree_nodeConstRef &function, bool void_as_null=true)
Return the return type of a function.
Class specification of the manager of the tree structures extracted from the raw file.
A brief description of the C++ Header File.
#define THROW_ASSERT(cond, str_expr)
helper function used to check an assert and if needed to throw an error in a standard way ...
Definition: exceptions.hpp:289

Generated on Mon Feb 12 2024 13:02:54 for PandA-2024.02 by doxygen 1.8.13