verilog: fix width/sign detection for functions

This commit is contained in:
Zachary Snow 2022-05-30 16:45:39 -04:00
parent cea7e85d60
commit a650d9079f
4 changed files with 55 additions and 5 deletions

View File

@ -14,6 +14,8 @@ Yosys 0.17 .. Yosys 0.17-dev
the remaining cases
- Fixed size and signedness computation for expressions containing array
querying functions
- Fixed size and signedness computation of functions used in ternary
expressions or case item expressions
Yosys 0.16 .. Yosys 0.17
--------------------------

View File

@ -1095,8 +1095,9 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
if (current_scope.count(str))
{
// This width detection is needed for function calls which are
// unelaborated, which currently only applies to calls to recursive
// functions reached by unevaluated ternary branches.
// unelaborated, which currently applies to calls to functions
// reached via unevaluated ternary branches or used in case or case
// item expressions.
const AstNode *func = current_scope.at(str);
if (func->type != AST_FUNCTION)
log_file_error(filename, location.first_line, "Function call to %s resolved to something that isn't a function!\n", RTLIL::unescape_id(str).c_str());
@ -1107,8 +1108,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
break;
}
log_assert(wire && wire->type == AST_WIRE);
sign_hint = wire->is_signed;
width_hint = 1;
sign_hint &= wire->is_signed;
int result_width = 1;
if (!wire->children.empty())
{
log_assert(wire->children.size() == 1);
@ -1121,10 +1122,11 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
if (left->type != AST_CONSTANT || right->type != AST_CONSTANT)
log_file_error(filename, location.first_line, "Function %s has non-constant width!",
RTLIL::unescape_id(str).c_str());
width_hint = abs(int(left->asInt(true) - right->asInt(true)));
result_width = abs(int(left->asInt(true) - right->asInt(true)));
delete left;
delete right;
}
width_hint = max(width_hint, result_width);
break;
}
YS_FALLTHROUGH

View File

@ -0,0 +1,42 @@
module top;
function automatic [30:0] func;
input integer inp;
func = { // self-determined context
(
inp == 0
? -1 // causes whole ternary to be 32 bits
: func(inp - 1) // 31 bits, unsigned
) >> 2};
endfunction
function automatic signed [3:0] dunk;
input integer inp;
dunk = (
inp == 0
? 4'hF
// shouldn't make the ternary signed
: dunk(inp - 1)
) == -1;
endfunction
localparam A = func(0);
localparam B = func(1);
localparam C = func(2);
localparam D = func(3);
localparam X = dunk(0);
localparam Y = dunk(1);
initial begin
assert(A == 31'h3F_FFFFFF);
assert(B == 31'h0F_FFFFFF);
assert(C == 31'h03_FFFFFF);
assert(D == 31'h00_FFFFFF);
assert(X == 0);
assert(Y == 0);
end
initial begin
logic x;
case (1'b1)
dunk(0): x = 0;
default: x = 1;
endcase
assert(x);
end
endmodule

View File

@ -0,0 +1,4 @@
read_verilog -sv func_tern_hint.sv
proc
opt
sat -verify -seq 1 -prove-asserts -show-all