diff options
Diffstat (limited to 'frontends')
-rw-r--r-- | frontends/ast/ast.cc | 31 | ||||
-rw-r--r-- | frontends/ast/ast.h | 4 | ||||
-rw-r--r-- | frontends/ast/simplify.cc | 22 |
3 files changed, 51 insertions, 6 deletions
diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 1ce7efc84..3af08b9d1 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -32,7 +32,7 @@ #include <sstream> #include <stdarg.h> -#include <assert.h> +#include <math.h> using namespace AST; using namespace AST_INTERNAL; @@ -760,6 +760,35 @@ bool AstNode::asBool() return false; } +int AstNode::isConst() +{ + if (type == AST_CONSTANT) + return 1; + if (type == AST_REALVALUE) + return 2; + return 0; +} + +double AstNode::asReal(bool is_signed) +{ + if (type == AST_CONSTANT) { + RTLIL::Const val; + val.bits = bits; + + double p = exp2(val.bits.size()-32); + if (val.bits.size() > 32) + val.bits.erase(val.bits.begin(), val.bits.begin()+(val.bits.size()-32)); + int32_t v = val.as_int() << (32-val.bits.size()); + + if (is_signed) + return v * p; + return uint32_t(v) * p; + } + if (type == AST_REALVALUE) + return realvalue; + return 0; +} + // create a new AstModule from an AST_MODULE AST node static AstModule* process_module(AstNode *ast, bool defer) { diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index aeb56e352..95f0f142f 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -240,6 +240,10 @@ namespace AST RTLIL::Const asAttrConst(); RTLIL::Const asParaConst(); bool asBool(); + + // helper functions for real valued const eval + int isConst(); // return '1' for AST_CONSTANT and '2' for AST_REALVALUE + double asReal(bool is_signed); }; // process an AST tree (ast must point to an AST_DESIGN node) and generate RTLIL code diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index fc040baac..7e4c265bd 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -32,7 +32,7 @@ #include <sstream> #include <stdarg.h> -#include <assert.h> +#include <math.h> using namespace AST; using namespace AST_INTERNAL; @@ -1433,10 +1433,22 @@ skip_dynamic_range_lvalue_expansion:; if (0) { case AST_MUL: const_func = RTLIL::const_mul; } if (0) { case AST_DIV: const_func = RTLIL::const_div; } if (0) { case AST_MOD: const_func = RTLIL::const_mod; } - if (children[0]->type == AST_CONSTANT && children[1]->type == AST_CONSTANT) { - RTLIL::Const y = const_func(children[0]->bitsAsConst(width_hint, sign_hint), - children[1]->bitsAsConst(width_hint, sign_hint), sign_hint, sign_hint, width_hint); - newNode = mkconst_bits(y.bits, sign_hint); + if (children[0]->isConst() && children[1]->isConst()) { + if (children[0]->isConst() + children[1]->isConst() > 2) { + newNode = new AstNode(AST_REALVALUE); + switch (type) { + case AST_ADD: newNode->realvalue = children[0]->asReal(sign_hint) + children[1]->asReal(sign_hint); break; + case AST_SUB: newNode->realvalue = children[0]->asReal(sign_hint) - children[1]->asReal(sign_hint); break; + case AST_MUL: newNode->realvalue = children[0]->asReal(sign_hint) * children[1]->asReal(sign_hint); break; + case AST_DIV: newNode->realvalue = children[0]->asReal(sign_hint) / children[1]->asReal(sign_hint); break; + case AST_MOD: newNode->realvalue = fmod(children[0]->asReal(sign_hint), children[1]->asReal(sign_hint)); break; + default: log_abort(); + } + } else { + RTLIL::Const y = const_func(children[0]->bitsAsConst(width_hint, sign_hint), + children[1]->bitsAsConst(width_hint, sign_hint), sign_hint, sign_hint, width_hint); + newNode = mkconst_bits(y.bits, sign_hint); + } } break; if (0) { case AST_POS: const_func = RTLIL::const_pos; } |