Skip to content

Commit 80a84d5

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

File tree

2 files changed

+165
-0
lines changed

2 files changed

+165
-0
lines changed

systemverilog-plugin/UhdmAst.cc

Lines changed: 164 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,50 @@ 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" ||
970+
current_node->str == "\\$size") {
971+
auto *id = current_node->children[0];
972+
unsigned dimension = (current_node->children.size() > 1) ? current_node->children[1]->integer : 1;
973+
974+
if (AST_INTERNAL::current_scope.count(id->str)) {
975+
auto *var = AST_INTERNAL::current_scope[id->str];
976+
AST::AstNode *range = nullptr;
977+
if (var->attributes.count(UhdmAst::unpacked_ranges())) {
978+
auto *unpacked_ranges = var->attributes[UhdmAst::unpacked_ranges()];
979+
if ((dimension - 1) < unpacked_ranges->children.size()) {
980+
range = unpacked_ranges->children[unpacked_ranges->children.size() - dimension];
981+
} else {
982+
dimension -= unpacked_ranges->children.size();
983+
}
984+
}
985+
if (!range && var->attributes.count(UhdmAst::packed_ranges())) {
986+
auto *packed_ranges = var->attributes[UhdmAst::packed_ranges()];
987+
if ((dimension - 1) < packed_ranges->children.size()) {
988+
range = packed_ranges->children[packed_ranges->children.size() - dimension];
989+
} else {
990+
std::cout << "Nonexistend dimension: " << dimension << " of " << id->str << std::endl;
991+
break;
992+
}
993+
}
994+
995+
AST::AstNode *c = nullptr;
996+
if (current_node->str == "\\$left")
997+
c = AST::AstNode::mkconst_int(!range->range_swapped ? range->range_left : range->range_right, true);
998+
else if (current_node->str == "\\$right")
999+
c = AST::AstNode::mkconst_int(!range->range_swapped ? range->range_right : range->range_left, true);
1000+
else if (current_node->str == "\\$low")
1001+
c = AST::AstNode::mkconst_int(std::min(range->range_left, range->range_right), true);
1002+
else if (current_node->str == "\\$high")
1003+
c = AST::AstNode::mkconst_int(std::max(range->range_left, range->range_right), true);
1004+
else if (current_node->str == "\\$size")
1005+
c = AST::AstNode::mkconst_int(
1006+
std::max(range->range_left, range->range_right) - std::min(range->range_left, range->range_right) + 1, true);
1007+
c->cloneInto(current_node);
1008+
delete c;
1009+
}
1010+
}
1011+
break;
9651012
default:
9661013
break;
9671014
}
@@ -3182,6 +3229,120 @@ void UhdmAst::process_for()
31823229
transform_breaks_continues(loop, current_node);
31833230
}
31843231

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