diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 8582c7eeb..f64ac4ac6 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -103,6 +103,23 @@ static vhdl_expr *translate_ulong(ivl_expr_t e) return new vhdl_const_int(ivl_expr_uvalue(e)); } +static vhdl_expr *translate_reduction(support_function_t f, bool neg, + vhdl_expr *operand) +{ + require_support_function(f); + vhdl_fcall *fcall = + new vhdl_fcall(support_function::function_name(f), + vhdl_type::std_logic()); + + vhdl_type std_logic_vector(VHDL_TYPE_STD_LOGIC_VECTOR); + fcall->add_expr(operand->cast(&std_logic_vector)); + if (neg) + return new vhdl_unaryop_expr(VHDL_UNARYOP_NOT, fcall, + vhdl_type::std_logic()); + else + return fcall; +} + static vhdl_expr *translate_unary(ivl_expr_t e) { vhdl_expr *operand = translate_expr(ivl_expr_oper1(e)); @@ -111,13 +128,15 @@ static vhdl_expr *translate_unary(ivl_expr_t e) bool should_be_signed = ivl_expr_signed(e) != 0; - if (operand->get_type()->get_name() == VHDL_TYPE_UNSIGNED && should_be_signed) { + if (operand->get_type()->get_name() == VHDL_TYPE_UNSIGNED + && should_be_signed) { //operand->print(); //std::cout << "^ should be signed but is not" << std::endl; operand = change_signedness(operand, true); } - else if (operand->get_type()->get_name() == VHDL_TYPE_SIGNED && !should_be_signed) { + else if (operand->get_type()->get_name() == VHDL_TYPE_SIGNED + && !should_be_signed) { //operand->print(); //std::cout << "^ should be unsigned but is not" << std::endl; @@ -131,20 +150,13 @@ static vhdl_expr *translate_unary(ivl_expr_t e) return new vhdl_unaryop_expr (VHDL_UNARYOP_NOT, operand, new vhdl_type(*operand->get_type())); case 'N': // NOR + return translate_reduction(SF_REDUCE_OR, true, operand); case '|': - { - require_support_function(SF_REDUCE_OR); - vhdl_fcall *f = - new vhdl_fcall(support_function::function_name(SF_REDUCE_OR), - vhdl_type::std_logic()); - - vhdl_type std_logic_vector(VHDL_TYPE_STD_LOGIC_VECTOR); - f->add_expr(operand->cast(&std_logic_vector)); - if ('N' == opcode) - return new vhdl_unaryop_expr(VHDL_UNARYOP_NOT, f, vhdl_type::std_logic()); - else - return f; - } + return translate_reduction(SF_REDUCE_OR, false, operand); + case 'A': // NAND + return translate_reduction(SF_REDUCE_AND, true, operand); + case '&': + return translate_reduction(SF_REDUCE_AND, false, operand); default: error("No translation for unary opcode '%c'\n", ivl_expr_opcode(e)); diff --git a/tgt-vhdl/lpm.cc b/tgt-vhdl/lpm.cc index 0a619c0df..3221b85c6 100644 --- a/tgt-vhdl/lpm.cc +++ b/tgt-vhdl/lpm.cc @@ -261,18 +261,18 @@ static vhdl_expr *lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) return part_select_pv_lpm_to_expr(scope, lpm); case IVL_LPM_UFUNC: return ufunc_lpm_to_expr(scope, lpm); - /*case IVL_LPM_RE_AND: - return reduction_lpm_to_expr(scope, lpm, "Reduce_AND", false); + case IVL_LPM_RE_AND: + return reduction_lpm_to_expr(scope, lpm, SF_REDUCE_AND, false); case IVL_LPM_RE_NAND: - return reduction_lpm_to_expr(scope, lpm, "Reduce_AND", true);*/ + return reduction_lpm_to_expr(scope, lpm, SF_REDUCE_AND, true); case IVL_LPM_RE_NOR: return reduction_lpm_to_expr(scope, lpm, SF_REDUCE_OR, true); case IVL_LPM_RE_OR: return reduction_lpm_to_expr(scope, lpm, SF_REDUCE_OR, false); - /*case IVL_LPM_RE_XOR: - return reduction_lpm_to_expr(scope, lpm, "Reduce_XOR", false); + case IVL_LPM_RE_XOR: + return reduction_lpm_to_expr(scope, lpm, SF_REDUCE_XOR, false); case IVL_LPM_RE_XNOR: - return reduction_lpm_to_expr(scope, lpm, "Reduce_XNOR", false);*/ + return reduction_lpm_to_expr(scope, lpm, SF_REDUCE_XOR, false); case IVL_LPM_SIGN_EXT: return sign_extend_lpm_to_expr(scope, lpm); case IVL_LPM_ARRAY: diff --git a/tgt-vhdl/support.cc b/tgt-vhdl/support.cc index 33c5bb4c8..159618739 100644 --- a/tgt-vhdl/support.cc +++ b/tgt-vhdl/support.cc @@ -42,6 +42,10 @@ const char *support_function::function_name(support_function_t type) return "Boolean_To_Logic"; case SF_REDUCE_OR: return "Reduce_OR"; + case SF_REDUCE_AND: + return "Reduce_AND"; + case SF_REDUCE_XOR: + return "Reduce_XOR"; default: assert(false); } @@ -55,6 +59,8 @@ vhdl_type *support_function::function_type(support_function_t type) return vhdl_type::boolean(); case SF_BOOLEAN_TO_LOGIC: case SF_REDUCE_OR: + case SF_REDUCE_AND: + case SF_REDUCE_XOR: return vhdl_type::std_logic(); default: assert(false); @@ -95,6 +101,26 @@ void support_function::emit(std::ostream &of, int level) const << "end loop;" << nl_string(indent(level)) << "return '0';" << nl_string(level); break; + case SF_REDUCE_AND: + of << "(X : std_logic_vector) return std_logic is" << nl_string(level) + << "begin" << nl_string(indent(level)) + << "for I in X'Range loop" << nl_string(indent(indent(level))) + << "if X(I) = '0' then" << nl_string(indent(indent(indent(level)))) + << "return '0';" << nl_string(indent(indent(level))) + << "end if;" << nl_string(indent(level)) + << "end loop;" << nl_string(indent(level)) + << "return '1';" << nl_string(level); + break; + case SF_REDUCE_XOR: + of << "(X : std_logic_vector) return std_logic is" + << nl_string(indent(level)) + << "variable R : std_logic := '0';" << nl_string(level) + << "begin" << nl_string(indent(level)) + << "for I in X'Range loop" << nl_string(indent(indent(level))) + << "R := X(I) xor R;" << nl_string(indent(level)) + << "end loop;" << nl_string(indent(level)) + << "return R;" << nl_string(level); + break; default: assert(false); } diff --git a/tgt-vhdl/support.hh b/tgt-vhdl/support.hh index eff12b3f3..a5e247c94 100644 --- a/tgt-vhdl/support.hh +++ b/tgt-vhdl/support.hh @@ -28,6 +28,8 @@ enum support_function_t { SF_SIGNED_TO_BOOLEAN, SF_BOOLEAN_TO_LOGIC, SF_REDUCE_OR, + SF_REDUCE_AND, + SF_REDUCE_XOR, }; class support_function : public vhdl_function {