diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 2425b1d2e..5f6f12b60 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -244,6 +244,39 @@ static vhdl_expr *translate_shift(vhdl_expr *lhs, vhdl_expr *rhs, return new vhdl_binop_expr(lhs, op, r_cast, rtype); } +/* + * The exponentiation operator in VHDL is not defined for numeric_std + * types. We can get around this by converting the operands to integers, + * performing the operation, then converting the result back to the + * original type. This will work OK in simulation but certainly will not + * synthesise unless the operands are constant. + * + * However, even this does not work quite correctly. The Integer type in + * VHDL is signed and usually only 32 bits, therefore any result larger + * than this will overflow and raise an exception. I can't see a way + * around this at the moment. + */ +static vhdl_expr *translate_power(ivl_expr_t e, vhdl_expr *lhs, vhdl_expr *rhs) +{ + vhdl_type integer(VHDL_TYPE_INTEGER); + vhdl_expr *lhs_int = lhs->cast(&integer); + vhdl_expr *rhs_int = rhs->cast(&integer); + + vhdl_expr *result = new vhdl_binop_expr(lhs_int, VHDL_BINOP_POWER, rhs_int, + vhdl_type::integer()); + + int width = ivl_expr_width(e); + const char *func = ivl_expr_signed(e) ? "To_Signed" : "To_Unsigned"; + vhdl_type *type = ivl_expr_signed(e) + ? vhdl_type::nsigned(width) : vhdl_type::nunsigned(width); + + vhdl_fcall *conv = new vhdl_fcall(func, type); + conv->add_expr(result); + conv->add_expr(new vhdl_const_int(width)); + + return conv; +} + static vhdl_expr *translate_binary(ivl_expr_t e) { vhdl_expr *lhs = translate_expr(ivl_expr_oper1(e)); @@ -358,6 +391,9 @@ static vhdl_expr *translate_binary(ivl_expr_t e) case '^': result = translate_numeric(lhs, rhs, VHDL_BINOP_XOR); break; + case 'p': // Power + result = translate_power(e, lhs, rhs); + break; default: error("No translation for binary opcode '%c'\n", ivl_expr_opcode(e)); diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 49cb82841..404b7a5c3 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -730,7 +730,7 @@ void vhdl_binop_expr::emit(std::ostream &of, int level) const const char* ops[] = { "and", "or", "=", "/=", "+", "-", "*", "<", ">", "<=", ">=", "sll", "srl", "xor", "&", - "nand", "nor", "xnor", "/", "mod", NULL + "nand", "nor", "xnor", "/", "mod", "**", NULL }; of << " " << ops[op_] << " "; diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 4d5141e98..349bf4e6e 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -91,6 +91,7 @@ enum vhdl_binop_t { VHDL_BINOP_XNOR, VHDL_BINOP_DIV, VHDL_BINOP_MOD, + VHDL_BINOP_POWER, }; /*