diff options
author | Clifford Wolf <clifford@clifford.at> | 2017-09-29 11:39:36 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-09-29 11:39:36 +0200 |
commit | 637a02eb5cf8ef09a7fb02af31d6149a31460d0f (patch) | |
tree | 1bf85e76f6258af1779520e8fda1c196ea758f7f | |
parent | 29f8acf09586c34222923139511ef64c00eccc8b (diff) | |
parent | e951ac0dfba554a86331b0863f7bda81effef10d (diff) | |
download | yosys-637a02eb5cf8ef09a7fb02af31d6149a31460d0f.tar.gz yosys-637a02eb5cf8ef09a7fb02af31d6149a31460d0f.tar.bz2 yosys-637a02eb5cf8ef09a7fb02af31d6149a31460d0f.zip |
Merge pull request #425 from udif/udif_dollar_bits
Add $bits() and $size()
-rw-r--r-- | frontends/ast/simplify.cc | 72 | ||||
-rw-r--r-- | tests/simple/functions01.sv | 32 |
2 files changed, 103 insertions, 1 deletions
diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 28c9945ab..678951850 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -387,7 +387,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, } for (size_t i = 0; i < children.size(); i++) { AstNode *node = children[i]; - if (node->type == AST_PARAMETER || node->type == AST_LOCALPARAM || node->type == AST_WIRE || node->type == AST_AUTOWIRE) + if (node->type == AST_PARAMETER || node->type == AST_LOCALPARAM || node->type == AST_WIRE || node->type == AST_AUTOWIRE || node->type == AST_MEMORY) while (node->simplify(true, false, false, 1, -1, false, node->type == AST_PARAMETER || node->type == AST_LOCALPARAM)) did_something = true; } @@ -1870,6 +1870,76 @@ skip_dynamic_range_lvalue_expansion:; goto apply_newNode; } + if (VERILOG_FRONTEND::sv_mode && (str == "\\$size" || str == "\\$bits")) + { + if (str == "\\$bits" && children.size() != 1) + log_error("System function %s got %d arguments, expected 1 at %s:%d.\n", + RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum); + + if (str == "\\$size" && children.size() != 1 && children.size() != 2) + log_error("System function %s got %d arguments, expected 1 or 2 at %s:%d.\n", + RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum); + + int dim = 1; + if (str == "\\$size" && children.size() == 2) { + AstNode *buf = children[1]->clone(); + // Evaluate constant expression + while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } + dim = buf->asInt(false); + delete buf; + } + AstNode *buf = children[0]->clone(); + int mem_depth = 1; + AstNode *id_ast = NULL; + + // Is this needed? + //while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } + buf->detectSignWidth(width_hint, sign_hint); + + if (buf->type == AST_IDENTIFIER) { + id_ast = buf->id2ast; + if (id_ast == NULL && current_scope.count(buf->str)) + id_ast = current_scope.at(buf->str); + if (!id_ast) + log_error("Failed to resolve identifier %s for width detection at %s:%d!\n", buf->str.c_str(), filename.c_str(), linenum); + if (id_ast->type == AST_MEMORY) { + // We got here only if the argument is a memory + // Otherwise $size() and $bits() return the expression width + AstNode *mem_range = id_ast->children[1]; + if (str == "\\$bits") { + if (mem_range->type == AST_RANGE) { + if (!mem_range->range_valid) + log_error("Failed to detect width of memory access `%s' at %s:%d!\n", buf->str.c_str(), filename.c_str(), linenum); + mem_depth = mem_range->range_left - mem_range->range_right + 1; + } else + log_error("Unknown memory depth AST type in `%s' at %s:%d!\n", buf->str.c_str(), filename.c_str(), linenum); + } else { + // $size() + if (mem_range->type == AST_RANGE) { + if (!mem_range->range_valid) + log_error("Failed to detect width of memory access `%s' at %s:%d!\n", buf->str.c_str(), filename.c_str(), linenum); + int dims; + if (id_ast->multirange_dimensions.empty()) + dims = 1; + else + dims = GetSize(id_ast->multirange_dimensions)/2; + if (dim == 1) + width_hint = (dims > 1) ? id_ast->multirange_dimensions[1] : (mem_range->range_left - mem_range->range_right + 1); + else if (dim <= dims) { + width_hint = id_ast->multirange_dimensions[2*dim-1]; + } else if ((dim > dims+1) || (dim < 0)) + log_error("Dimension %d out of range in `%s', as it only has dimensions 1..%d at %s:%d!\n", dim, buf->str.c_str(), dims+1, filename.c_str(), linenum); + } else + log_error("Unknown memory depth AST type in `%s' at %s:%d!\n", buf->str.c_str(), filename.c_str(), linenum); + } + } + } + delete buf; + + newNode = mkconst_int(width_hint * mem_depth, false); + goto apply_newNode; + } + if (str == "\\$ln" || str == "\\$log10" || str == "\\$exp" || str == "\\$sqrt" || str == "\\$pow" || str == "\\$floor" || str == "\\$ceil" || str == "\\$sin" || str == "\\$cos" || str == "\\$tan" || str == "\\$asin" || str == "\\$acos" || str == "\\$atan" || str == "\\$atan2" || str == "\\$hypot" || diff --git a/tests/simple/functions01.sv b/tests/simple/functions01.sv new file mode 100644 index 000000000..d7ce2326e --- /dev/null +++ b/tests/simple/functions01.sv @@ -0,0 +1,32 @@ +module functions01; + +wire [5:2]x; +wire [3:0]y[2:7]; +wire [3:0]z[7:2][2:9]; + +//wire [$size(x)-1:0]x_size; +//wire [$size({x, x})-1:0]xx_size; +//wire [$size(y)-1:0]y_size; +//wire [$size(z)-1:0]z_size; + +assert property ($size(x) == 4); +assert property ($size({3{x}}) == 3*4); +assert property ($size(y) == 6); +assert property ($size(y, 1) == 6); +assert property ($size(y, (1+1)) == 4); + +assert property ($size(z) == 6); +assert property ($size(z, 1) == 6); +assert property ($size(z, 2) == 8); +assert property ($size(z, 3) == 4); +// This should trigger an error if enabled (it does). +//assert property ($size(z, 4) == 4); + +//wire [$bits(x)-1:0]x_bits; +//wire [$bits({x, x})-1:0]xx_bits; + +assert property ($bits(x) == 4); +assert property ($bits(y) == 4*6); +assert property ($bits(z) == 4*6*8); + +endmodule |