kernel: require \B_SIGNED=0 on $shl, $sshl, $shr, $sshr.

Before this commit, these cells would accept any \B_SIGNED and in
case of \B_SIGNED=1, would still treat the \B input as unsigned.

Also fix the Verilog frontend to never emit such constructs.
This commit is contained in:
whitequark 2019-12-04 11:59:36 +00:00
parent ec4c9267b3
commit e97e33d00d
2 changed files with 26 additions and 8 deletions

View File

@ -2242,7 +2242,7 @@ gen_stmt:
ast_stack.back()->children.push_back(node);
ast_stack.push_back(node);
} opt_arg_list ';'{
ast_stack.pop_back();
ast_stack.pop_back();
};
gen_stmt_block:
@ -2413,19 +2413,19 @@ basic_expr:
append_attr($$, $2);
} |
basic_expr OP_SHL attr basic_expr {
$$ = new AstNode(AST_SHIFT_LEFT, $1, $4);
$$ = new AstNode(AST_SHIFT_LEFT, $1, new AstNode(AST_TO_UNSIGNED, $4));
append_attr($$, $3);
} |
basic_expr OP_SHR attr basic_expr {
$$ = new AstNode(AST_SHIFT_RIGHT, $1, $4);
$$ = new AstNode(AST_SHIFT_RIGHT, $1, new AstNode(AST_TO_UNSIGNED, $4));
append_attr($$, $3);
} |
basic_expr OP_SSHL attr basic_expr {
$$ = new AstNode(AST_SHIFT_SLEFT, $1, $4);
$$ = new AstNode(AST_SHIFT_SLEFT, $1, new AstNode(AST_TO_UNSIGNED, $4));
append_attr($$, $3);
} |
basic_expr OP_SSHR attr basic_expr {
$$ = new AstNode(AST_SHIFT_SRIGHT, $1, $4);
$$ = new AstNode(AST_SHIFT_SRIGHT, $1, new AstNode(AST_TO_UNSIGNED, $4));
append_attr($$, $3);
} |
basic_expr '<' attr basic_expr {

View File

@ -783,6 +783,14 @@ namespace {
return v;
}
int param_bool(RTLIL::IdString name, bool expected)
{
int v = param_bool(name);
if (v != expected)
error(__LINE__);
return v;
}
void param_bits(RTLIL::IdString name, int width)
{
param(name);
@ -869,13 +877,23 @@ namespace {
return;
}
if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx))) {
if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr))) {
param_bool(ID(A_SIGNED));
param_bool(ID(B_SIGNED), /*expected=*/false);
port(ID::A, param(ID(A_WIDTH)));
port(ID::B, param(ID(B_WIDTH)));
port(ID::Y, param(ID(Y_WIDTH)));
check_expected(/*check_matched_sign=*/false);
return;
}
if (cell->type.in(ID($shift), ID($shiftx))) {
param_bool(ID(A_SIGNED));
param_bool(ID(B_SIGNED));
port(ID::A, param(ID(A_WIDTH)));
port(ID::B, param(ID(B_WIDTH)));
port(ID::Y, param(ID(Y_WIDTH)));
check_expected(false);
check_expected(/*check_matched_sign=*/false);
return;
}
@ -957,7 +975,7 @@ namespace {
port(ID::A, param(ID(A_WIDTH)));
port(ID::B, param(ID(B_WIDTH)));
port(ID::Y, param(ID(Y_WIDTH)));
check_expected(false);
check_expected(/*check_matched_sign=*/false);
return;
}