systemc-clang 2.0.0
Parsing SystemC constructs
Loading...
Searching...
No Matches
HDLHnode.cpp
Go to the documentation of this file.
1// clang-format off
2
3#include <assert.h>
4#include "HDLHnode.h"
5
6#include "assert.h"
7
8#include "clang/Basic/Diagnostic.h"
9
10// clang-format on
11
13#undef DEBUG_TYPE
14#define DEBUG_TYPE "HDL"
15
22namespace systemc_hdl {
23
24 bool is_numeric(string &s) {
25 for (char c : s) {
26 if (!isdigit(c)) return false;
27 }
28 return true;
29 }
31
32 hp->child_list.erase( std::remove_if( hp->child_list.begin(), hp->child_list.end(), [] (hNodep x) {
33 return (
34 //((x->h_op==hNode::hdlopsEnum::hVarAssign) &&
35 //(x->child_list.size()==2) &&
36 //(x->child_list.back()->h_op != hNode::hdlopsEnum::hLiteral)) ||
37 (x->h_op == hNode::hdlopsEnum::hVardecl) || // index variables
38 //(x->h_op == hNode::hdlopsEnum::hMethodCall) || // sc_method
39 (x->h_op == hNode::hdlopsEnum::hReturnStmt) || // remove return stmt in init block
40 (x->h_op == hNode::hdlopsEnum::hUnimpl));}), hp->child_list.end() );
41
42 for (hNodep hpi :hp->child_list)
43 RemoveSCMethod(hpi);
44 }
45
47 for (hNodep hpi :hp->child_list)
48 CleanupInitHcode(hpi);
49 hp->child_list.erase( std::remove_if( hp->child_list.begin(), hp->child_list.end(), [] (hNodep x) {
50 return (((x->h_op==hNode::hdlopsEnum::hBinop) &&
51 (x->h_name==pbstring) || (x->h_name==sensop)) ||
52 ((x->h_op == hNode::hdlopsEnum::hSensvar) && // gratuitous sim method sens vars
53 (x->child_list[0]->h_name.find(localstr) != std::string::npos)) ||
54 (x->h_op==hNode::hdlopsEnum::hForStmt) ||
55 (x->h_op == hNode::hdlopsEnum::hVardeclrn) || // renamed index variables
56 ((x->h_op==hNode::hdlopsEnum::hCStmt) &&
57 (x->child_list.empty())) ||
58 (x->h_op==hNode::hdlopsEnum::hVarAssign) ||
59 ((x->h_op == hNode::hdlopsEnum::hVarref) && (x->h_name == "sensitive")) ||
60 (isMorF(x->h_op) && (x->h_name.find(strsccore) !=std::string::npos)) ||
61 ((x->h_op == hNode::hdlopsEnum::hNoop) &&
62 (x->h_name==arrsub)));}), hp->child_list.end());
63 // for (hNodep hpi :hp->child_list)
64 // CleanupInitHcode(hpi);
65
66 }
67
97
98 void HDLConstructorHcode::PushRange(hNodep &hp, std::vector<for_info_t> &for_info) {
99
100 for_info_t tmp{"FORNAME", 0, 1, 1, 0};
101
102 hNodep hlo = hp->child_list[0];
103 hNodep hi = hp->child_list[1];
104 hNodep hstep = hp->child_list[2];
105
106 if ((hlo->h_op == hNode::hdlopsEnum::hVarAssign) &&
107 (hlo->child_list.size() == 2) &&
108 (hlo->child_list[0]-> h_op == hNode::hdlopsEnum::hVarref) &&
109 (hlo->child_list[1]->h_op == hNode::hdlopsEnum::hLiteral)) {
110 tmp.name = hlo->child_list[0]->h_name;
111 //FIXME -- put in error message if not a numeric constant
112 if (is_numeric(hlo->child_list[1]->h_name))
113 tmp.lo = stoi(hlo->child_list[1]->h_name);
114 }
115 if ((hi->h_op == hNode::hdlopsEnum::hBinop) &&
116 (hlo->child_list.size() == 2) &&
117 (hlo->child_list[0]-> h_op == hNode::hdlopsEnum::hVarref) &&
118 (hlo->child_list[1]->h_op == hNode::hdlopsEnum::hLiteral)) {
119 //FIXME -- check that names are same ... tmp.name = hi->child_list[0]->h_name;
120 //FIXME -- put in error message if not a numeric constant
121 if (is_numeric(hi->child_list[1]->h_name))
122 tmp.hi = stoi(hi->child_list[1]->h_name);
123 }
124 for_info.push_back(tmp);
125
126 }
127
128 void HDLConstructorHcode::PopRange(std::vector<for_info_t> &for_info) {
129 for_info.pop_back();
130 }
131
132 void HDLConstructorHcode::SubstituteIndex(hNodep &hp, std::vector<for_info_t> &for_info) {
133 for (int i=0; i < for_info.size(); i++) {
134 if ((hp->h_op == hNode::hdlopsEnum::hVarref) && (hp->h_name == for_info[i].name)) {
135 hp->h_name = to_string(for_info[i].curix);
136 hp->h_op = hNode::hdlopsEnum::hLiteral;
137 break;
138 }
139 }
140 for (hNodep hpi : hp->child_list)
141 SubstituteIndex(hpi, for_info);
142 }
143
145 hNodep h_ret = new hNode(hp->h_name, hp->h_op);
146 for (hNodep hchild : hp->child_list) {
147 h_ret->child_list.push_back(HnodeDeepCopy(hchild));
148 }
149 return h_ret;
150 }
151
153 string tmpstr;
154 if (hp == NULL) return "";
155 if (hp->getopc() == hNode::hdlopsEnum::hVarref) {
156 tmpstr = hp->getname();
157 hp->set(tmpstr.substr(tmpstr.find(fielddelim)+fielddelim.size()));
158 return tmpstr.substr(0, tmpstr.find(fielddelim));
159 }
160 for (auto hp1: hp->child_list) {
161 tmpstr = ExtractModuleName(hp1);
162 if (tmpstr!="") return tmpstr;
163 }
164 return "";
165 }
166
167 // Generate a port binding
168 // need to dismantle modname##field:
169 // modname is the h_name for the portbinding
170 // and field is the varref, e.g.
171 // Case 0: hBinop () [
172 // hVarref u_fwd_cast##clk NOLIST
173 // hVarref clk NOLIST
174 // but if the submod instance/port is ARRAYSUBSCRIPT in loop,
175 // can have (if submodule is not an array of submods)
176 // Case 1: hBinop () [
177 // hBinop ARRAYSUBSCRIPT [
178 // hVarref u_fwd_cast##m_block NOLIST
179 // hVarref _local_0 NOLIST
180 // ]
181 // hBinop ARRAYSUBSCRIPT [
182 // hVarref c_fc_block NOLIST
183 // hVarref _local_0 NOLIST
184 // ]
185 // ]
186 // ]
187
188 // or it will look like this if submod is array ( u_yt[_local_0].clk:clk )
189 // Case 2: hBinop () [
190 // hVarref clk [
191 // hBinop ARRAYSUBSCRIPT [
192 // hVarref u_yt NOLIST
193 // hVarref _local_0 NOLIST
194 // ]
195 // ]
196 // hVarref clk NOLIST
197 // ]
198 // or for module instance array ref and port array ref
199 //
200 // Case 3: hBinop () [
201 // hBinop ARRAYSUBSCRIPT [
202 // hVarref m_port [
203 // hBinop ARRAYSUBSCRIPT [
204 // hVarref u_xt NOLIST
205 // hVarref _local_0 NOLIST
206 // ]
207 // ]
208 // hVarref _local_1 NOLIST
209 // ]
210 // hBinop ARRAYSUBSCRIPT [
211 // hBinop ARRAYSUBSCRIPT [
212 // hVarref c_xt_data NOLIST
213 // hVarref _local_0 NOLIST
214 // ]
215 // hVarref _local_1 NOLIST
216 // ]
217 // ]
218 void HDLConstructorHcode::UnrollBinding(hNodep &hp_orig, std::vector<for_info_t> &for_info) {
219
220 assert ((hp_orig->h_op == hNode::hdlopsEnum::hBinop) && (hp_orig->h_name == pbstring));
221
222 // Case 0
223 if (for_info.empty()) { // simple case, not in a for loop
224 string submodport;
225 string thismodsig;
226 hNodep hpb;
227 if (hp_orig->child_list[0]->getopc() == hNode::hdlopsEnum::hVarref) {
228 submodport = hp_orig->child_list[0]->h_name;
229 // part before delimiter is submodule name, after delimiter is port name
230
231 hpb = new hNode(submodport.substr(0, submodport.find(fielddelim)),
232 hNode::hdlopsEnum::hPortbinding);
233 hpb->child_list.push_back(new hNode(submodport.substr(submodport.find(fielddelim)+fielddelim.size()),
234 hNode::hdlopsEnum::hVarref));
235 }
236 else {
237 submodport = ExtractModuleName(hp_orig->child_list[0]);
238 hpb = new hNode(submodport, hNode::hdlopsEnum::hPortbinding);
239 hpb->append(hp_orig->child_list[0]); // need to remove module name
240 }
241 if (hp_orig->child_list[1]->getopc() == hNode::hdlopsEnum::hVarref) {
242 thismodsig = hp_orig->child_list[1]->h_name;
243 hpb->child_list.push_back(new hNode(thismodsig, hNode::hdlopsEnum::hVarref));
244 }
245 else {
246 hpb->append(hp_orig->child_list[1]); // need to remove module name
247 }
248 hnewpb->child_list.push_back(hpb);
249 return;
250 }
251
252 hNodep hp = HnodeDeepCopy(hp_orig); // will be modifying subtrees, so make a copy
253
254 hNodep hsubmodport = hp->child_list[0]; // submoduleport being bound
255 hNodep hthismodsig = hp->child_list[1];
256
257 string submodport{"XXX"}, thismodsig{"YYY"};
258 string submod{"SUBMOD"};
259
260 // Case 2
261 if ((hsubmodport->h_op == hNode::hdlopsEnum::hVarref) && (hsubmodport->child_list.size() > 0)) {
262
263 // in a for loop, unroll the port bindings
264 // hVarref clk [
265 // hBinop ARRAYSUBSCRIPT [
266 // hVarref u_yt NOLIST
267 // hVarref _local_0 NOLIST // changed to hLiteral by Substitute index
268 // ]
269 // ]
270 // hVarref clk NOLIST
271 // ]
272 hNodep hportchild = hsubmodport->child_list[0];
273 hNodep hparent = hsubmodport;
274 std::vector<hNodep> hmodarrix;
275 // look for submodule name
276 while ((hportchild != nullptr) && (hportchild->h_name == arrsub)) {
277 hmodarrix.push_back(hportchild->child_list[1]); // save i in A[i]
278 if ((hportchild->child_list[0]->h_op == hNode::hdlopsEnum::hVarref) &&
279 (hportchild->child_list[0]->child_list.empty())) { // simple varref of A
280 submod = hportchild->child_list[0]->h_name;
281 break;
282 }
283 hparent = hportchild;
284 hportchild = hportchild->child_list[0];
285 }
286 for (hNodep hsubmodixname:hmodarrix) {
287 // assume simple case of "i" not "i+1" or "i+j"
288 assert((hsubmodixname->h_op == hNode::hdlopsEnum::hVarref) && "Submodule index must be simple loop variable name");
289 string ixname = hsubmodixname->h_name;
290 for (int i = 0; i < for_info.size(); i++) {
291 if (for_info[i].name == ixname) {
292 submod+=tokendelim+to_string(for_info[i].curix);
293 break;
294 }
295 }
296 }
297 if (hsubmodport->child_list[0]->h_name == arrsub) {
298 hsubmodport->child_list.erase(hsubmodport->child_list.begin());
299 }
300 }
301 else if (hsubmodport->h_name == arrsub) { // check Case 1, 3
302 // Case 1: hBinop () [
303 // hBinop ARRAYSUBSCRIPT [
304 // hVarref u_fwd_cast##m_block NOLIST
305 // hVarref _local_0 NOLIST
306 // ]
307 // hBinop ARRAYSUBSCRIPT [
308 // hVarref c_fc_block NOLIST
309 // hVarref _local_0 NOLIST
310 // ]
311 // ]
312 // ]
313
314 // Case 3: hBinop () [
315 // hBinop ARRAYSUBSCRIPT [
316 // hVarref m_port [
317 // hBinop ARRAYSUBSCRIPT [
318 // hVarref u_xt NOLIST
319 // hVarref _local_0 NOLIST
320 // ]
321 // ]
322 // hVarref _local_1 NOLIST
323 // ]
324 // hBinop ARRAYSUBSCRIPT [
325 // hBinop ARRAYSUBSCRIPT [
326 // hVarref c_xt_data NOLIST
327 // hVarref _local_0 NOLIST
328 // ]
329 // hVarref _local_1 NOLIST
330 // ]
331 // ]
332
333 hNodep hportchild = hsubmodport->child_list[0];
334 hNodep hparent = hsubmodport;
335 std::vector<hNodep> hmodarrix;
336
337 while ((hportchild != nullptr) &&
338 ((hportchild->h_name == arrsub) ||
339 ((hportchild->h_op == hNode::hdlopsEnum::hVarref) &&
340 (hportchild->child_list.size() > 0)))) {
341 if (hportchild->h_name == arrsub) {
342 hmodarrix.push_back(hportchild->child_list[1]); // save i in A[i]
343 }
344 hparent = hportchild;
345 hportchild = hportchild->child_list[0];
346 }
347 if ((hportchild != nullptr) && (hportchild->h_op == hNode::hdlopsEnum::hVarref)) {
348 if (hportchild->child_list.empty()) { // Case 1
349 submod = hportchild->h_name;
350 size_t found = submod.find(fielddelim);
351 if ( found != std::string::npos) { // module name prefix, not a vector of modules
352 hportchild->h_name = submod.substr(found+fielddelim.size());
353 submod = submod.substr(0, found);
354 }
355 else { // Varref has child; need to handle Case 3 by removing the (arraysubscript submod ix) node
356 for (hNodep hsubmodixname:hmodarrix) {
357 // assume simple case of "i" not "i+1" or "i+j"
358 assert((hsubmodixname->h_op == hNode::hdlopsEnum::hVarref) && "Submodule index must be simple loop variable name");
359 string ixname = hsubmodixname->h_name;
360 for (int i = 0; i < for_info.size(); i++) {
361 if (for_info[i].name == ixname) {
362 submod+=tokendelim+to_string(for_info[i].curix);
363 break;
364 }
365 }
366 }
367 hparent = hsubmodport;
368 hportchild = hsubmodport->child_list[0];
369 while ((hportchild != nullptr) && (hportchild->h_name != arrsub)) {
370 hparent = hportchild;
371 hportchild = hportchild->child_list[0];
372 }
373 if (hportchild != nullptr) { // it's an array subscript
374 hparent->child_list.erase(hparent->child_list.begin());
375 }
376 }
377 }
378 }
379 }
380
381 hNodep hpb = new hNode( submod, hNode::hdlopsEnum::hPortbinding);
382 //hpb->child_list.push_back(new hNode(submodport+tokendelim+to_string(i), hNode::hdlopsEnum::hVarref));
383 //hpb->child_list.push_back(new hNode(thismodsig+tokendelim+to_string(i), hNode::hdlopsEnum::hVarref));
384
385 hpb->child_list.push_back(hsubmodport);
386 hpb->child_list.push_back(hthismodsig);
387 SubstituteIndex(hpb, for_info);
388 hnewpb->child_list.push_back(hpb);
389 }
391
392 // hMethodCall sc_coresc_simcontextcreate_method_process:create_method_process [
393 // hMethodCall sc_coresc_get_curr_simcontext:sc_get_curr_simcontext NOLIST
394 // hUnimpl StringLiteral NOLIST
395 // hLiteral 0 NOLIST
396 // hUnop & [
397 // hMethodCall zhwencode_blockfp_t11_52_2mc_proc:mc_proc NOLIST
398 // ]
399 // hUnimpl CXXThisExpr NOLIST
400 // hLiteral 0 NOLIST
401 // ]
402
403 if (isMorF(hp->h_op)) {
404 for (hNodep hpi: hp->child_list) {
405 if (hpi->h_op == hNode::hdlopsEnum::hUnop) {
406 std::size_t found = (hpi->child_list[0]->h_name).find(qualnamedelim);
407 if ( found != std::string::npos) { // should be SC_METHOD name
408 hnewsens.push_back(new hNode(hpi->child_list[0]->h_name.substr(found+1),
409 hNode::hdlopsEnum::hSenslist));
410 return true; // got the name
411 }
412 else { // couldn't find the ":"
413 hnewsens.push_back(new hNode(hpi->child_list[0]->h_name, hNode::hdlopsEnum::hSenslist));
414 return true;
415 }
416 }
417 }
418 }
419 return false;
420 }
421
422 void HDLConstructorHcode::UnrollSensitem(hNodep &hp_orig, std::vector<for_info_t> &for_info) {
423 // hBinop << [
424 // hVarref sensitive NOLIST
425 // hNoop pos [
426 // hVarref clk NOLIST
427 // ]
428 // ]
429
430 // check for list of sens items
431 if (isInitSensitem(hp_orig->child_list[0])) {
432 UnrollSensitem(hp_orig->child_list[0], for_info);
433 }
434
435 // at a primitive sens item
436 hNodep hp = HnodeDeepCopy(hp_orig); // need to keep the subtrees when the original tree gets released
437
438 hp->h_op = hNode::hdlopsEnum::hSensvar;
439 hp->h_name = noname;
440
441 delete hp->child_list[0]; // release that hnode
442 hp->child_list.erase(hp->child_list.begin()); // remove the first item
443 if (!for_info.empty()) {
444 SubstituteIndex(hp, for_info);
445 }
446
447 // check for edge sensitivity
448 // eg
449 // hSensvar pos [ <-- hp
450 // hNoop pos [ <-- hedge
451 // hVarref clk NOLIST <-- hedge->child_list[0]
452 // ]
453 // ]
454
455 if (isEdge(hp->child_list[0]->h_name)) {
456 hNodep hedge = hp->child_list[0];
457 hp->child_list[0] = hedge->child_list[0];
458 hedge->child_list.pop_back();
459 hp->child_list.push_back(hedge);
460 }
461 else {
462
463 if (isSimEvent(hp->child_list[0]->h_name)) {
464
465 // hSensvar NONAME [
466 // hNoop value_changed_event [
467 // hVarref c_fp##ready NOLIST
468 // ]
469 // hNoop always NOLIST
470 // ]
471
472 hNodep htmp = hp->child_list[0]->child_list[0];
473 hp->child_list.erase(hp->child_list.begin());
474 hp->child_list.push_back(htmp);
475 }
476
477 hp->child_list.push_back(new hNode("always", hNode::hdlopsEnum::hNoop));
478 };
479
480 hnewsens.back()->child_list.push_back(hp);
481 }
482
483 void HDLConstructorHcode::HDLLoop(hNodep &hp, std::vector<for_info_t> &for_info ) {
484 // check in order of expected frequency
485 if (isInitPB(hp)) {
486 UnrollBinding(hp, for_info);
487 }
488 else if (isInitSensitem(hp)) {
489 UnrollSensitem(hp, for_info);
490 }
491
492 else if ((hp->h_op == hNode::hdlopsEnum::hForStmt) && (hp->child_list.size() > 3)) {
493 PushRange(hp, for_info); // fill in name, lo, hi, step
494 for (int forloopix = for_info.back().lo; forloopix < for_info.back().hi; forloopix+=for_info.back().step) {
495 for_info.back().curix = forloopix;
496 for (int i=3; i<hp->child_list.size(); i++) {
497 if (isInitPB(hp->child_list[i])) {// hcode indicating port binding
498 UnrollBinding(hp->child_list[i], for_info); // unroll all bindings in this range
499 }
500 else if (isInitSensitem(hp->child_list[i])) { // hcode indicating sensitivity item
501 UnrollSensitem(hp->child_list[i], for_info); // unroll all sensitems in this range
502 }
503 else if ((hp->child_list[i]->h_op == hNode::hdlopsEnum::hForStmt) ||
504 (hp->child_list[i]->h_op == hNode::hdlopsEnum::hCStmt))
505 HDLLoop(hp->child_list[i], for_info);
506 }
507 }
508 for_info.pop_back();
509 }
510 else if (hp->h_op == hNode::hdlopsEnum::hCStmt) {
511 for (hNodep hpc:hp->child_list) {
512 HDLLoop(hpc, for_info);
513 }
514 }
515 else if (isMethodCall(hp)) { // hVarAssign child[1] is a method call;
516 if (!SetupSenslist(hp->child_list[1])) { // points to first hMethodCall, push SC_METHOD name onto hnewsens
517 // oops couldn't parse it
518 hnewsens.push_back(new hNode( "METHOD ???", hNode::hdlopsEnum::hSenslist));
519 }
520 }
521 else {
522 // check for thread sensitivity declarations
523 int threadsensitem = isThreadSensitem(hp);
524 if (threadsensitem >0 ) {
525 // e.g. hMethodCall sc_core__sc_module__async_reset_signal_is:async_reset_signal_is [
526 // hVarref reset NOLIST
527 // hLiteral 0 NOLIST
528 // ]
529 LLVM_DEBUG(llvm::dbgs() << "HDLHNode: found thread sens item " << "\n");
530 hNodep hpsens = HnodeDeepCopy(hp); // need to keep the subtrees when the original tree gets released
531
532 hpsens->set(hNode::hdlopsEnum::hSensvar, threadsensitem == reset_async? "ASYNC": "SYNC");
533 if (hnewsens.size()==0) // this shouldn't be the case, but whatever
534 hnewsens.push_back(new hNode( "METHOD ???", hNode::hdlopsEnum::hSenslist));
535 hnewsens.back()->append(hpsens);
536 }
537 }
538 }
539
540
542
543 std::vector<for_info_t> for_info;
544
545 if (xconstructor==nullptr) return xconstructor;
546
547 // this is a workaround to make lldb find dumphcode
548 // since lldb doesn't pick up default parameters in print
549 // and doesn't recognize llvm::outs()
550 { int junk =2; if (junk!=2) xconstructor->dumphcode();}
551
552 RemoveSCMethod(xconstructor);
553 hnewpb = new hNode(xconstructor->h_name, hNode::hdlopsEnum::hPortbindings);
554 // FIXME name should be the SC_METHOD name
555 //hnewsens = new hNode(xconstructor->h_name, hNode::hdlopsEnum::hSenslist);
556 for (hNodep hp : xconstructor->child_list)
557 HDLLoop(hp, for_info);
558 if (!hnewpb->child_list.empty()) {
559 xconstructor->child_list.push_back(hnewpb);
560 }
561 if (!hnewsens.empty()) {
562 xconstructor->child_list.insert( xconstructor->child_list.end(), hnewsens.begin(), hnewsens.end());
563 }
564 CleanupInitHcode(xconstructor);
565 return xconstructor;
566 }
567
568}
void dumphcode()
Definition hNode.h:211
hdlopsEnum h_op
Definition hNode.h:107
hdlopsEnum getopc()
Definition hNode.h:173
string getname()
Definition hNode.h:169
string h_name
Definition hNode.h:106
void set(hdlopsEnum h, string s="")
Definition hNode.h:148
std::vector< hNodep > child_list
Definition hNode.h:109
void append(hNodep hnew)
Definition hNode.h:157
void UnrollSensitem(hNodep &hp_orig, std::vector< for_info_t > &for_info)
Definition HDLHnode.cpp:422
void UnrollBinding(hNodep &hp_orig, std::vector< for_info_t > &for_info)
Definition HDLHnode.cpp:218
void SubstituteIndex(hNodep &hp, std::vector< for_info_t > &for_info)
Definition HDLHnode.cpp:132
hNodep ProcessCXXConstructorHcode(hNodep xconstructor)
Definition HDLHnode.cpp:541
void PushRange(hNodep &hp, std::vector< for_info_t > &for_info)
Definition HDLHnode.cpp:98
void CleanupInitHcode(hNodep &hp)
Definition HDLHnode.cpp:46
string ExtractModuleName(hNodep hp)
Definition HDLHnode.cpp:152
void PopRange(std::vector< for_info_t > &for_info)
Definition HDLHnode.cpp:128
void RemoveSCMethod(hNodep &hp)
Definition HDLHnode.cpp:30
hNodep HnodeDeepCopy(hNodep hp)
Definition HDLHnode.cpp:144
void HDLLoop(hNodep &hp, std::vector< for_info_t > &for_info)
Definition HDLHnode.cpp:483
std::vector< hNodep > hnewsens
Definition HDLHnode.h:103
std::string to_string(T *pointer)
Definition ProcessDecl.h:18
bool is_numeric(string &s)
Definition HDLHnode.cpp:24