From f3b4a9dd2466d243fdb1b4ebf8c5e1e0d05d21af Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 14 Jun 2014 13:36:23 +0200 Subject: [PATCH] Added support for math functions --- frontends/ast/simplify.cc | 70 +++++++++++++++++++++++++++++++++++++++ tests/simple/realexpr.v | 57 +++++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index a5c4d0230..89dc8ef73 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1215,6 +1215,10 @@ skip_dynamic_range_lvalue_expansion:; { if (str == "\\$clog2") { + if (children.size() != 1) + log_error("System function %s got %d arguments, expected 1 at %s:%d.\n", + RTLIL::id2cstr(str), int(children.size()), filename.c_str(), linenum); + AstNode *buf = children[0]->clone(); while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } if (buf->type != AST_CONSTANT) @@ -1230,6 +1234,72 @@ skip_dynamic_range_lvalue_expansion:; 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" || + str == "\\$sinh" || str == "\\$cosh" || str == "\\$tanh" || str == "\\$asinh" || str == "\\$acosh" || str == "\\$atanh") + { + bool func_with_two_arguments = str == "\\$pow" || str == "\\$atan2" || str == "\\$hypot"; + double x = 0, y = 0; + + if (func_with_two_arguments) { + if (children.size() != 2) + log_error("System function %s got %d arguments, expected 2 at %s:%d.\n", + RTLIL::id2cstr(str), int(children.size()), filename.c_str(), linenum); + } else { + if (children.size() != 1) + log_error("System function %s got %d arguments, expected 1 at %s:%d.\n", + RTLIL::id2cstr(str), int(children.size()), filename.c_str(), linenum); + } + + if (children.size() >= 1) { + while (children[0]->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } + if (!children[0]->isConst()) + log_error("Failed to evaluate system function `%s' with non-constant argument at %s:%d.\n", + RTLIL::id2cstr(str), filename.c_str(), linenum); + int child_width_hint = width_hint; + bool child_sign_hint = sign_hint; + children[0]->detectSignWidth(child_width_hint, child_sign_hint); + x = children[0]->asReal(child_sign_hint); + } + + if (children.size() >= 2) { + while (children[1]->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } + if (!children[1]->isConst()) + log_error("Failed to evaluate system function `%s' with non-constant argument at %s:%d.\n", + RTLIL::id2cstr(str), filename.c_str(), linenum); + int child_width_hint = width_hint; + bool child_sign_hint = sign_hint; + children[1]->detectSignWidth(child_width_hint, child_sign_hint); + y = children[1]->asReal(child_sign_hint); + } + + newNode = new AstNode(AST_REALVALUE); + if (str == "\\$ln") newNode->realvalue = log(x); + else if (str == "\\$log10") newNode->realvalue = log10(x); + else if (str == "\\$exp") newNode->realvalue = exp(x); + else if (str == "\\$sqrt") newNode->realvalue = sqrt(x); + else if (str == "\\$pow") newNode->realvalue = pow(x, y); + else if (str == "\\$floor") newNode->realvalue = floor(x); + else if (str == "\\$ceil") newNode->realvalue = ceil(x); + else if (str == "\\$sin") newNode->realvalue = sin(x); + else if (str == "\\$cos") newNode->realvalue = cos(x); + else if (str == "\\$tan") newNode->realvalue = tan(x); + else if (str == "\\$asin") newNode->realvalue = asin(x); + else if (str == "\\$acos") newNode->realvalue = acos(x); + else if (str == "\\$atan") newNode->realvalue = atan(x); + else if (str == "\\$atan2") newNode->realvalue = atan2(x, y); + else if (str == "\\$hypot") newNode->realvalue = hypot(x, y); + else if (str == "\\$sinh") newNode->realvalue = sinh(x); + else if (str == "\\$cosh") newNode->realvalue = cosh(x); + else if (str == "\\$tanh") newNode->realvalue = tanh(x); + else if (str == "\\$asinh") newNode->realvalue = asinh(x); + else if (str == "\\$acosh") newNode->realvalue = acosh(x); + else if (str == "\\$atanh") newNode->realvalue = atanh(x); + else log_abort(); + goto apply_newNode; + } + if (current_scope.count(str) == 0 || current_scope[str]->type != AST_FUNCTION) log_error("Can't resolve function name `%s' at %s:%d.\n", str.c_str(), filename.c_str(), linenum); } diff --git a/tests/simple/realexpr.v b/tests/simple/realexpr.v index 47f81214a..2b63ca6f9 100644 --- a/tests/simple/realexpr.v +++ b/tests/simple/realexpr.v @@ -1,3 +1,4 @@ + module demo_001(y1, y2, y3, y4); output [7:0] y1, y2, y3, y4; @@ -11,3 +12,59 @@ module demo_001(y1, y2, y3, y4); assign y3 = p3 + 0.2; assign y4 = p4 + 0.2; endmodule + +module demo_002(s, a, y); + input [4:0] s; + input [3:0] a; + output [7:0] y; + + reg [7:0] data [21*16-1:0]; + integer i; + + initial begin + for (i = 0; i < 16; i = i+1) begin + data[ 0*16 + i] = 128 + 64 * $ln (i*0.2 - 0.8); + data[ 1*16 + i] = 128 + 64 * $log10 (i*0.2 - 0.8); + data[ 2*16 + i] = 128 + 64 * $exp (i*0.2 - 0.8); + data[ 3*16 + i] = 128 + 64 * $sqrt (i*0.2 - 0.8); + data[ 4*16 + i] = 128 + 64 * $floor (i*0.2 - 0.8); + data[ 5*16 + i] = 128 + 64 * $ceil (i*0.2 - 0.8); + data[ 6*16 + i] = 128 + 64 * $sin (i*0.2 - 0.8); + data[ 7*16 + i] = 128 + 64 * $cos (i*0.2 - 0.8); + data[ 8*16 + i] = 128 + 64 * $tan (i*0.2 - 0.8); + data[ 9*16 + i] = 128 + 64 * $asin (i*0.2 - 0.8); + data[10*16 + i] = 128 + 64 * $acos (i*0.2 - 0.8); + data[11*16 + i] = 128 + 64 * $atan (i*0.2 - 0.8); + data[12*16 + i] = 128 + 64 * $sinh (i*0.2 - 0.8); + data[13*16 + i] = 128 + 64 * $cosh (i*0.2 - 0.8); + data[14*16 + i] = 128 + 64 * $tanh (i*0.2 - 0.8); + data[15*16 + i] = 128 + 64 * $asinh (i*0.2 - 0.8); + data[16*16 + i] = 128 + 64 * $acosh (i*0.2 - 0.8); + data[17*16 + i] = 128 + 64 * $atanh (i*0.2 - 0.8); + end + end + + assign y = s < 18 ? data[s*16 + a] : 0; +endmodule + +module demo_003(s, a, b, y); + input [1:0] s; + input [3:0] a; + input [3:0] b; + output [7:0] y; + + reg [7:0] data [3*16*16-1:0]; + integer i, j; + + initial begin + for (i = 0; i < 16; i = i+1) + for (j = 0; j < 16; j = j+1) begin + data[0*256 + i*16 + j] = 128 + 64 * $pow (i*0.2 - 0.8, j*0.2 - 0.8); + data[1*256 + i*16 + j] = 128 + 64 * $atan2 (i*0.2 - 0.8, j*0.2 - 0.8); + data[2*256 + i*16 + j] = 128 + 64 * $hypot (i*0.2 - 0.8, j*0.2 - 0.8); + end + end + + assign y = s < 3 ? data[s*256 + a*16 + b] : 0; +endmodule + -- 2.30.2