Fix casting with signed/unsigned expressions
Previously the code generator tried to infer the VHDL types. Now it takes a much more dumb approach and forces the VHDL type to be the same as the ivl type (derived from ivl_expr_signed and ivl_expr_width) in the expression tree. This works much better :-)
This commit is contained in:
parent
bd5cc96956
commit
1cd7689d03
157
tgt-vhdl/expr.cc
157
tgt-vhdl/expr.cc
|
|
@ -69,6 +69,39 @@ static vhdl_expr *translate_unary(ivl_expr_t e)
|
||||||
if (NULL == operand)
|
if (NULL == operand)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
bool should_be_signed = ivl_expr_signed(e) != 0;
|
||||||
|
|
||||||
|
if (operand->get_type()->get_name() == VHDL_TYPE_UNSIGNED && should_be_signed) {
|
||||||
|
//operand->print();
|
||||||
|
//std::cout << "^ should be signed but is not" << std::endl;
|
||||||
|
|
||||||
|
int msb = operand->get_type()->get_msb();
|
||||||
|
int lsb = operand->get_type()->get_lsb();
|
||||||
|
vhdl_type u(VHDL_TYPE_SIGNED, msb, lsb);
|
||||||
|
|
||||||
|
operand = operand->cast(&u);
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
|
||||||
|
int msb = operand->get_type()->get_msb();
|
||||||
|
int lsb = operand->get_type()->get_lsb();
|
||||||
|
vhdl_type u(VHDL_TYPE_UNSIGNED, msb, lsb);
|
||||||
|
|
||||||
|
operand = operand->cast(&u);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Need to ensure that the operand is interpreted as unsigned to get VHDL
|
||||||
|
// to emulate Verilog behaviour
|
||||||
|
if (operand->get_type()->get_name() == VHDL_TYPE_SIGNED) {
|
||||||
|
int msb = operand->get_type()->get_msb();
|
||||||
|
int lsb = operand->get_type()->get_lsb();
|
||||||
|
vhdl_type u(VHDL_TYPE_UNSIGNED, msb, lsb);
|
||||||
|
|
||||||
|
operand = operand->cast(&u);
|
||||||
|
}
|
||||||
|
|
||||||
char opcode = ivl_expr_opcode(e);
|
char opcode = ivl_expr_opcode(e);
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
case '!':
|
case '!':
|
||||||
|
|
@ -156,75 +189,89 @@ static vhdl_expr *translate_binary(ivl_expr_t e)
|
||||||
|
|
||||||
int lwidth = lhs->get_type()->get_width();
|
int lwidth = lhs->get_type()->get_width();
|
||||||
int rwidth = rhs->get_type()->get_width();
|
int rwidth = rhs->get_type()->get_width();
|
||||||
|
|
||||||
std::cout << "opwidth = " << ivl_expr_width(e)
|
|
||||||
<< " lwidth = " << lwidth
|
|
||||||
<< " rwidth = " << rwidth << std::endl;
|
|
||||||
|
|
||||||
// May need to resize the left or right hand side
|
|
||||||
/*if (lwidth < rwidth) {
|
|
||||||
lhs = lhs->cast(rhs->get_type());
|
|
||||||
}
|
|
||||||
else if (rwidth < lwidth) {
|
|
||||||
rhs = rhs->cast(lhs->get_type());
|
|
||||||
}*/
|
|
||||||
|
|
||||||
int result_width = ivl_expr_width(e);
|
int result_width = ivl_expr_width(e);
|
||||||
|
|
||||||
// For === and !== we need to compare std_logic_vectors
|
// For === and !== we need to compare std_logic_vectors
|
||||||
// rather than signeds
|
// rather than signeds
|
||||||
vhdl_type std_logic_vector(VHDL_TYPE_STD_LOGIC_VECTOR, result_width-1, 0);
|
vhdl_type std_logic_vector(VHDL_TYPE_STD_LOGIC_VECTOR, result_width-1, 0);
|
||||||
|
vhdl_type_name_t ltype = lhs->get_type()->get_name();
|
||||||
|
vhdl_type_name_t rtype = rhs->get_type()->get_name();
|
||||||
bool vectorop =
|
bool vectorop =
|
||||||
(lhs->get_type()->get_name() == VHDL_TYPE_SIGNED
|
(ltype == VHDL_TYPE_SIGNED || ltype == VHDL_TYPE_UNSIGNED) &&
|
||||||
|| lhs->get_type()->get_name() == VHDL_TYPE_UNSIGNED) &&
|
(rtype == VHDL_TYPE_SIGNED || rtype == VHDL_TYPE_UNSIGNED);
|
||||||
(rhs->get_type()->get_name() == VHDL_TYPE_SIGNED
|
|
||||||
|| rhs->get_type()->get_name() == VHDL_TYPE_UNSIGNED);
|
|
||||||
|
|
||||||
|
// May need to resize the left or right hand side
|
||||||
|
if (vectorop) {
|
||||||
|
if (lwidth < rwidth)
|
||||||
|
lhs = lhs->resize(rwidth);
|
||||||
|
else if (rwidth < lwidth)
|
||||||
|
rhs = rhs->resize(lwidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
vhdl_expr *result;
|
||||||
switch (ivl_expr_opcode(e)) {
|
switch (ivl_expr_opcode(e)) {
|
||||||
case '+':
|
case '+':
|
||||||
return translate_numeric(lhs, rhs, VHDL_BINOP_ADD);
|
result = translate_numeric(lhs, rhs, VHDL_BINOP_ADD);
|
||||||
|
break;
|
||||||
case '-':
|
case '-':
|
||||||
return translate_numeric(lhs, rhs, VHDL_BINOP_SUB);
|
result = translate_numeric(lhs, rhs, VHDL_BINOP_SUB);
|
||||||
|
break;
|
||||||
case '*':
|
case '*':
|
||||||
return translate_numeric(lhs, rhs, VHDL_BINOP_MULT);
|
result = translate_numeric(lhs, rhs, VHDL_BINOP_MULT);
|
||||||
|
break;
|
||||||
case 'e':
|
case 'e':
|
||||||
return translate_relation(lhs, rhs, VHDL_BINOP_EQ);
|
result = translate_relation(lhs, rhs, VHDL_BINOP_EQ);
|
||||||
|
break;
|
||||||
case 'E':
|
case 'E':
|
||||||
if (vectorop)
|
if (vectorop)
|
||||||
return translate_relation(lhs->cast(&std_logic_vector),
|
result = translate_relation(lhs->cast(&std_logic_vector),
|
||||||
rhs->cast(&std_logic_vector), VHDL_BINOP_EQ);
|
rhs->cast(&std_logic_vector), VHDL_BINOP_EQ);
|
||||||
else
|
else
|
||||||
return translate_relation(lhs, rhs, VHDL_BINOP_EQ);
|
result = translate_relation(lhs, rhs, VHDL_BINOP_EQ);
|
||||||
|
break;
|
||||||
case 'n':
|
case 'n':
|
||||||
return translate_relation(lhs, rhs, VHDL_BINOP_NEQ);
|
result = translate_relation(lhs, rhs, VHDL_BINOP_NEQ);
|
||||||
|
break;
|
||||||
case 'N':
|
case 'N':
|
||||||
if (vectorop)
|
if (vectorop)
|
||||||
return translate_relation(lhs->cast(&std_logic_vector),
|
result = translate_relation(lhs->cast(&std_logic_vector),
|
||||||
rhs->cast(&std_logic_vector), VHDL_BINOP_NEQ);
|
rhs->cast(&std_logic_vector), VHDL_BINOP_NEQ);
|
||||||
else
|
else
|
||||||
return translate_relation(lhs, rhs, VHDL_BINOP_NEQ);
|
result = translate_relation(lhs, rhs, VHDL_BINOP_NEQ);
|
||||||
|
break;
|
||||||
case '&': // Bitwise AND
|
case '&': // Bitwise AND
|
||||||
return translate_numeric(lhs, rhs, VHDL_BINOP_AND);
|
result = translate_numeric(lhs, rhs, VHDL_BINOP_AND);
|
||||||
|
break;
|
||||||
case 'a': // Logical AND
|
case 'a': // Logical AND
|
||||||
return translate_logical(lhs, rhs, VHDL_BINOP_AND);
|
result = translate_logical(lhs, rhs, VHDL_BINOP_AND);
|
||||||
|
break;
|
||||||
case '|': // Bitwise OR
|
case '|': // Bitwise OR
|
||||||
return translate_numeric(lhs, rhs, VHDL_BINOP_OR);
|
result = translate_numeric(lhs, rhs, VHDL_BINOP_OR);
|
||||||
|
break;
|
||||||
case 'o': // Logical OR
|
case 'o': // Logical OR
|
||||||
return translate_logical(lhs, rhs, VHDL_BINOP_OR);
|
result = translate_logical(lhs, rhs, VHDL_BINOP_OR);
|
||||||
|
break;
|
||||||
case '<':
|
case '<':
|
||||||
return translate_relation(lhs, rhs, VHDL_BINOP_LT);
|
result = translate_relation(lhs, rhs, VHDL_BINOP_LT);
|
||||||
|
break;
|
||||||
case 'L':
|
case 'L':
|
||||||
return translate_relation(lhs, rhs, VHDL_BINOP_LEQ);
|
result = translate_relation(lhs, rhs, VHDL_BINOP_LEQ);
|
||||||
|
break;
|
||||||
case '>':
|
case '>':
|
||||||
return translate_relation(lhs, rhs, VHDL_BINOP_GT);
|
result = translate_relation(lhs, rhs, VHDL_BINOP_GT);
|
||||||
|
break;
|
||||||
case 'G':
|
case 'G':
|
||||||
return translate_relation(lhs, rhs, VHDL_BINOP_GEQ);
|
result = translate_relation(lhs, rhs, VHDL_BINOP_GEQ);
|
||||||
|
break;
|
||||||
case 'l':
|
case 'l':
|
||||||
return translate_shift(lhs, rhs, VHDL_BINOP_SL);
|
result = translate_shift(lhs, rhs, VHDL_BINOP_SL);
|
||||||
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
return translate_shift(lhs, rhs, VHDL_BINOP_SR);
|
result = translate_shift(lhs, rhs, VHDL_BINOP_SR);
|
||||||
|
break;
|
||||||
case '^':
|
case '^':
|
||||||
return translate_numeric(lhs, rhs, VHDL_BINOP_XOR);
|
result = translate_numeric(lhs, rhs, VHDL_BINOP_XOR);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
error("No translation for binary opcode '%c'\n",
|
error("No translation for binary opcode '%c'\n",
|
||||||
ivl_expr_opcode(e));
|
ivl_expr_opcode(e));
|
||||||
|
|
@ -232,6 +279,42 @@ static vhdl_expr *translate_binary(ivl_expr_t e)
|
||||||
delete rhs;
|
delete rhs;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (NULL == result)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (vectorop) {
|
||||||
|
bool should_be_signed = ivl_expr_signed(e) != 0;
|
||||||
|
|
||||||
|
if (result->get_type()->get_name() == VHDL_TYPE_UNSIGNED && should_be_signed) {
|
||||||
|
//result->print();
|
||||||
|
//std::cout << "^ should be signed but is not" << std::endl;
|
||||||
|
|
||||||
|
int msb = result->get_type()->get_msb();
|
||||||
|
int lsb = result->get_type()->get_lsb();
|
||||||
|
vhdl_type u(VHDL_TYPE_SIGNED, msb, lsb);
|
||||||
|
|
||||||
|
result = result->cast(&u);
|
||||||
|
}
|
||||||
|
else if (result->get_type()->get_name() == VHDL_TYPE_SIGNED && !should_be_signed) {
|
||||||
|
//result->print();
|
||||||
|
//std::cout << "^ should be unsigned but is not" << std::endl;
|
||||||
|
|
||||||
|
int msb = result->get_type()->get_msb();
|
||||||
|
int lsb = result->get_type()->get_lsb();
|
||||||
|
vhdl_type u(VHDL_TYPE_SIGNED, msb, lsb);
|
||||||
|
|
||||||
|
result = result->cast(&u);
|
||||||
|
}
|
||||||
|
|
||||||
|
int actual_width = result->get_type()->get_width();
|
||||||
|
if (actual_width != result_width) {
|
||||||
|
//result->print();
|
||||||
|
//std::cout << "^ should be " << result_width << " but is " << actual_width << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static vhdl_expr *translate_select(ivl_expr_t e)
|
static vhdl_expr *translate_select(ivl_expr_t e)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue