|
1 | 1 | #include <algorithm> |
| 2 | +#include <cstdlib> |
2 | 3 | #include <cstring> |
3 | 4 | #include <functional> |
4 | 5 | #include <regex> |
5 | 6 | #include <string> |
| 7 | +#include <string_view> |
6 | 8 | #include <vector> |
7 | 9 |
|
8 | 10 | #include "UhdmAst.h" |
9 | 11 | #include "frontends/ast/ast.h" |
10 | 12 | #include "libs/sha1/sha1.h" |
| 13 | +#include "uhdm/sv_vpi_user.h" |
11 | 14 |
|
12 | 15 | // UHDM |
13 | 16 | #include <uhdm/uhdm.h> |
@@ -962,6 +965,50 @@ static void simplify(AST::AstNode *current_node, AST::AstNode *parent_node) |
962 | 965 | if (current_node->str == "$display" || current_node->str == "$write") |
963 | 966 | simplify_format_string(current_node); |
964 | 967 | 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; |
965 | 1012 | default: |
966 | 1013 | break; |
967 | 1014 | } |
@@ -3182,6 +3229,120 @@ void UhdmAst::process_for() |
3182 | 3229 | transform_breaks_continues(loop, current_node); |
3183 | 3230 | } |
3184 | 3231 |
|
| 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 | + |
3185 | 3346 | void UhdmAst::process_gen_scope() |
3186 | 3347 | { |
3187 | 3348 | current_node = make_ast_node(AST::AST_GENBLOCK); |
@@ -4180,6 +4341,9 @@ AST::AstNode *UhdmAst::process_object(vpiHandle obj_handle) |
4180 | 4341 | case vpiFor: |
4181 | 4342 | process_for(); |
4182 | 4343 | break; |
| 4344 | + case vpiForeachStmt: |
| 4345 | + process_foreach(); |
| 4346 | + break; |
4183 | 4347 | case vpiBreak: |
4184 | 4348 | // Will be resolved later by loop processor |
4185 | 4349 | current_node = make_ast_node(static_cast<AST::AstNodeType>(AST::AST_BREAK)); |
|
0 commit comments