Skip to content

Commit 389eb85

Browse files
author
Mariusz Glebocki
committed
Initial foreach loop support.
1 parent 0713ed7 commit 389eb85

File tree

2 files changed

+154
-0
lines changed

2 files changed

+154
-0
lines changed

systemverilog-plugin/UhdmAst.cc

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
#include <algorithm>
2+
#include <cstdlib>
23
#include <cstring>
34
#include <functional>
45
#include <regex>
56
#include <string>
7+
#include <string_view>
68
#include <vector>
79

810
#include "UhdmAst.h"
911
#include "frontends/ast/ast.h"
1012
#include "libs/sha1/sha1.h"
13+
#include "uhdm/sv_vpi_user.h"
1114

1215
// UHDM
1316
#include <uhdm/uhdm.h>
@@ -962,6 +965,44 @@ static void simplify(AST::AstNode *current_node, AST::AstNode *parent_node)
962965
if (current_node->str == "$display" || current_node->str == "$write")
963966
simplify_format_string(current_node);
964967
break;
968+
case AST::AST_FCALL:
969+
if (current_node->str == "\\$left" || current_node->str == "\\$right" || current_node->str == "\\$high" || current_node->str == "\\$low" || current_node->str == "\\$size") {
970+
auto* id = current_node->children[0];
971+
unsigned dimension = (current_node->children.size() > 1) ? current_node->children[1]->integer : 1;
972+
973+
if (AST_INTERNAL::current_scope.count(id->str)) {
974+
auto* var = AST_INTERNAL::current_scope[id->str];
975+
AST::AstNode* range = nullptr;
976+
if (var->attributes.count(UhdmAst::unpacked_ranges())) {
977+
auto* unpacked_ranges = var->attributes[UhdmAst::unpacked_ranges()];
978+
if ((dimension - 1) < unpacked_ranges->children.size()) {
979+
range = unpacked_ranges->children[unpacked_ranges->children.size() - dimension];
980+
} else {
981+
dimension -= unpacked_ranges->children.size();
982+
}
983+
}
984+
if (!range && var->attributes.count(UhdmAst::packed_ranges())) {
985+
auto* packed_ranges = var->attributes[UhdmAst::packed_ranges()];
986+
if ((dimension - 1) < packed_ranges->children.size()) {
987+
range = packed_ranges->children[packed_ranges->children.size() - dimension];
988+
} else {
989+
std::cout << "Nonexistend dimension: " << dimension << " of " << id->str << std::endl;
990+
break;
991+
}
992+
}
993+
994+
995+
AST::AstNode* c = nullptr;
996+
if (current_node->str == "\\$left") c = AST::AstNode::mkconst_int(!range->range_swapped ? range->range_left : range->range_right, true);
997+
else if (current_node->str == "\\$right") c = AST::AstNode::mkconst_int(!range->range_swapped ? range->range_right : range->range_left, true);
998+
else if (current_node->str == "\\$low") c = AST::AstNode::mkconst_int(std::min(range->range_left, range->range_right), true);
999+
else if (current_node->str == "\\$high") c = AST::AstNode::mkconst_int(std::max(range->range_left, range->range_right), true);
1000+
else if (current_node->str == "\\$size") c = AST::AstNode::mkconst_int(std::max(range->range_left, range->range_right) - std::min(range->range_left, range->range_right) + 1, true);
1001+
c->cloneInto(current_node);
1002+
delete c;
1003+
}
1004+
}
1005+
break;
9651006
default:
9661007
break;
9671008
}
@@ -3182,6 +3223,115 @@ void UhdmAst::process_for()
31823223
transform_breaks_continues(loop, current_node);
31833224
}
31843225

3226+
void UhdmAst::process_foreach()
3227+
{
3228+
// One of: packed array, unpacked array, string var
3229+
AST::AstNode* var_id = nullptr;
3230+
visit_one_to_one({vpiVariables}, obj_h, [&](AST::AstNode *node) { var_id = node; });
3231+
3232+
AST::AstNode *loop_body;
3233+
visit_one_to_one({vpiStmt}, obj_h, [&](AST::AstNode *node) { loop_body = node; });
3234+
3235+
struct id_dimension_pair {
3236+
std::string id;
3237+
int dimension;
3238+
};
3239+
std::vector<id_dimension_pair> loop_var_ids;
3240+
{
3241+
int current_dimension = 1;
3242+
visit_one_to_many({vpiLoopVars}, obj_h, [&](AST::AstNode *node) {
3243+
loop_var_ids.push_back({std::move(node->str), current_dimension});
3244+
++current_dimension;
3245+
delete node;
3246+
});
3247+
}
3248+
3249+
auto loop_id = shared.next_loop_id();
3250+
current_node = loop_body;
3251+
for (auto it = loop_var_ids.rbegin(); it != loop_var_ids.rend(); ++it) {
3252+
// FIXME: use real range
3253+
auto* idx_var_id = make_identifier(it->id);
3254+
3255+
auto* left = make_ast_node(AST::AST_FCALL, {
3256+
var_id->clone(),
3257+
AST::AstNode::mkconst_int(it->dimension, true),
3258+
});
3259+
left->str = "\\$left";
3260+
auto* right = make_ast_node(AST::AST_FCALL, {
3261+
var_id->clone(),
3262+
AST::AstNode::mkconst_int(it->dimension, true),
3263+
});
3264+
right->str = "\\$right";
3265+
auto* low = make_ast_node(AST::AST_FCALL, {
3266+
var_id->clone(),
3267+
AST::AstNode::mkconst_int(it->dimension, true),
3268+
});
3269+
low->str = "\\$low";
3270+
auto* high = make_ast_node(AST::AST_FCALL, {
3271+
var_id->clone(),
3272+
AST::AstNode::mkconst_int(it->dimension, true),
3273+
});
3274+
high->str = "\\$high";
3275+
3276+
auto* init_expr = make_ast_node(AST::AST_ASSIGN_EQ, {
3277+
idx_var_id->clone(),
3278+
left->clone(),
3279+
});
3280+
3281+
auto *cond_expr = make_ast_node(AST::AST_LOGIC_AND, {
3282+
make_ast_node(AST::AST_GE, {
3283+
idx_var_id->clone(),
3284+
low,
3285+
}),
3286+
make_ast_node(AST::AST_LE, {
3287+
idx_var_id->clone(),
3288+
high,
3289+
}),
3290+
});
3291+
3292+
auto *mod_expr = make_ast_node(AST::AST_ASSIGN_EQ, {
3293+
idx_var_id->clone(),
3294+
make_ast_node(AST::AST_ADD, {
3295+
idx_var_id,
3296+
make_ast_node(AST::AST_TERNARY, {
3297+
make_ast_node(AST::AST_LT, {
3298+
left,
3299+
right,
3300+
}),
3301+
AST::AstNode::mkconst_int(1, true),
3302+
AST::AstNode::mkconst_int(-1, true),
3303+
}),
3304+
}),
3305+
});
3306+
3307+
auto* body_block = make_ast_node(AST::AST_BLOCK, {current_node});
3308+
body_block->str = "$loop_" + std::to_string(loop_id) + "_" + std::to_string(it->dimension);
3309+
3310+
auto* for_loop = make_ast_node(AST::AST_FOR, {
3311+
init_expr,
3312+
cond_expr,
3313+
mod_expr,
3314+
body_block,
3315+
});
3316+
for_loop->str = body_block->str;
3317+
3318+
auto* wire = make_ast_node(AST::AST_WIRE, {make_range(31, 0, true)});
3319+
wire->str = it->id;
3320+
wire->is_reg = true;
3321+
wire->is_signed = true;
3322+
wire->range_left = -1;
3323+
wire->range_right = 0;
3324+
3325+
auto* fordecl_block = make_ast_node(AST::AST_BLOCK, {
3326+
for_loop,
3327+
wire,
3328+
});
3329+
fordecl_block->str = "$fordecl_block_" + std::to_string(loop_id) + "_" + std::to_string(it->dimension);
3330+
3331+
current_node = fordecl_block;
3332+
}
3333+
}
3334+
31853335
void UhdmAst::process_gen_scope()
31863336
{
31873337
current_node = make_ast_node(AST::AST_GENBLOCK);
@@ -4180,6 +4330,9 @@ AST::AstNode *UhdmAst::process_object(vpiHandle obj_handle)
41804330
case vpiFor:
41814331
process_for();
41824332
break;
4333+
case vpiForeachStmt:
4334+
process_foreach();
4335+
break;
41834336
case vpiBreak:
41844337
// Will be resolved later by loop processor
41854338
current_node = make_ast_node(static_cast<AST::AstNodeType>(AST::AST_BREAK));

systemverilog-plugin/UhdmAst.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ class UhdmAst
118118
void process_var_select();
119119
void process_if_else();
120120
void process_for();
121+
void process_foreach();
121122
void process_gen_scope_array();
122123
void process_gen_scope();
123124
void process_case();

0 commit comments

Comments
 (0)