Added support for math functions
authorClifford Wolf <clifford@clifford.at>
Sat, 14 Jun 2014 11:36:23 +0000 (13:36 +0200)
committerClifford Wolf <clifford@clifford.at>
Sat, 14 Jun 2014 11:36:23 +0000 (13:36 +0200)
frontends/ast/simplify.cc
tests/simple/realexpr.v

index a5c4d0230c0160cb08e80eed40b18142a2daed9c..89dc8ef73548d2277895e67aba98204e4b3bad94 100644 (file)
@@ -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);
                }
index 47f81214a31d5f522a95970b732a844c3819c7f8..2b63ca6f9fed762612462c572c5e308917009516 100644 (file)
@@ -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
+