mirror of
https://github.com/YosysHQ/yosys
synced 2025-06-06 06:03:23 +00:00
read_verilog: allow width detect to fail for unreachable ternary branch
Cannot skip width detection entirely as unreachable branch (if it is a legal expression) may still be used to determine width of result
This commit is contained in:
parent
95a313e837
commit
61c3ad6791
3 changed files with 39 additions and 19 deletions
|
@ -250,8 +250,8 @@ namespace AST
|
||||||
void dumpVlog(FILE *f, std::string indent) const;
|
void dumpVlog(FILE *f, std::string indent) const;
|
||||||
|
|
||||||
// used by genRTLIL() for detecting expression width and sign
|
// used by genRTLIL() for detecting expression width and sign
|
||||||
void detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *found_real = NULL);
|
void detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *found_real = NULL, bool can_fail = false);
|
||||||
void detectSignWidth(int &width_hint, bool &sign_hint, bool *found_real = NULL);
|
void detectSignWidth(int &width_hint, bool &sign_hint, bool *found_real = NULL, bool can_fail = false);
|
||||||
|
|
||||||
// create RTLIL code for this AST node
|
// create RTLIL code for this AST node
|
||||||
// for expressions the resulting signal vector is returned
|
// for expressions the resulting signal vector is returned
|
||||||
|
|
|
@ -580,7 +580,7 @@ struct AST_INTERNAL::ProcessGenerator
|
||||||
};
|
};
|
||||||
|
|
||||||
// detect sign and width of an expression
|
// detect sign and width of an expression
|
||||||
void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *found_real)
|
void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *found_real, bool can_fail)
|
||||||
{
|
{
|
||||||
std::string type_name;
|
std::string type_name;
|
||||||
bool sub_sign_hint = true;
|
bool sub_sign_hint = true;
|
||||||
|
@ -610,8 +610,11 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
|
||||||
id_ast = id2ast;
|
id_ast = id2ast;
|
||||||
if (id_ast == NULL && current_scope.count(str))
|
if (id_ast == NULL && current_scope.count(str))
|
||||||
id_ast = current_scope.at(str);
|
id_ast = current_scope.at(str);
|
||||||
if (!id_ast)
|
if (!id_ast) {
|
||||||
|
if (can_fail)
|
||||||
|
return;
|
||||||
log_file_error(filename, linenum, "Failed to resolve identifier %s for width detection!\n", str.c_str());
|
log_file_error(filename, linenum, "Failed to resolve identifier %s for width detection!\n", str.c_str());
|
||||||
|
}
|
||||||
if (id_ast->type == AST_PARAMETER || id_ast->type == AST_LOCALPARAM) {
|
if (id_ast->type == AST_PARAMETER || id_ast->type == AST_LOCALPARAM) {
|
||||||
if (id_ast->children.size() > 1 && id_ast->children[1]->range_valid) {
|
if (id_ast->children.size() > 1 && id_ast->children[1]->range_valid) {
|
||||||
this_width = id_ast->children[1]->range_left - id_ast->children[1]->range_right + 1;
|
this_width = id_ast->children[1]->range_left - id_ast->children[1]->range_right + 1;
|
||||||
|
@ -769,8 +772,10 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_TERNARY:
|
case AST_TERNARY:
|
||||||
children.at(1)->detectSignWidthWorker(width_hint, sign_hint, found_real);
|
children.at(1)->detectSignWidthWorker(width_hint, sign_hint, found_real,
|
||||||
children.at(2)->detectSignWidthWorker(width_hint, sign_hint, found_real);
|
children.at(0)->type == AST_CONSTANT && !children.at(0)->asBool() /* can_fail */);
|
||||||
|
children.at(2)->detectSignWidthWorker(width_hint, sign_hint, found_real,
|
||||||
|
children.at(0)->type == AST_CONSTANT && children.at(0)->asBool() /* can_fail */);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AST_MEMRD:
|
case AST_MEMRD:
|
||||||
|
@ -817,13 +822,13 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
|
||||||
}
|
}
|
||||||
|
|
||||||
// detect sign and width of an expression
|
// detect sign and width of an expression
|
||||||
void AstNode::detectSignWidth(int &width_hint, bool &sign_hint, bool *found_real)
|
void AstNode::detectSignWidth(int &width_hint, bool &sign_hint, bool *found_real, bool can_fail)
|
||||||
{
|
{
|
||||||
width_hint = -1;
|
width_hint = -1;
|
||||||
sign_hint = true;
|
sign_hint = true;
|
||||||
if (found_real)
|
if (found_real)
|
||||||
*found_real = false;
|
*found_real = false;
|
||||||
detectSignWidthWorker(width_hint, sign_hint, found_real);
|
detectSignWidthWorker(width_hint, sign_hint, found_real, can_fail);
|
||||||
}
|
}
|
||||||
|
|
||||||
// create RTLIL from an AST node
|
// create RTLIL from an AST node
|
||||||
|
@ -1334,18 +1339,31 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
||||||
detectSignWidth(width_hint, sign_hint);
|
detectSignWidth(width_hint, sign_hint);
|
||||||
|
|
||||||
RTLIL::SigSpec cond = children[0]->genRTLIL();
|
RTLIL::SigSpec cond = children[0]->genRTLIL();
|
||||||
RTLIL::SigSpec val1 = children[1]->genRTLIL(width_hint, sign_hint);
|
RTLIL::SigSpec sig;
|
||||||
RTLIL::SigSpec val2 = children[2]->genRTLIL(width_hint, sign_hint);
|
if (cond.is_fully_const()) {
|
||||||
|
if (cond.as_bool()) {
|
||||||
|
sig = children[1]->genRTLIL(width_hint, sign_hint);
|
||||||
|
widthExtend(this, sig, sig.size(), children[1]->is_signed);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sig = children[2]->genRTLIL(width_hint, sign_hint);
|
||||||
|
widthExtend(this, sig, sig.size(), children[2]->is_signed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
RTLIL::SigSpec val1 = children[1]->genRTLIL(width_hint, sign_hint);
|
||||||
|
RTLIL::SigSpec val2 = children[2]->genRTLIL(width_hint, sign_hint);
|
||||||
|
|
||||||
if (cond.size() > 1)
|
if (cond.size() > 1)
|
||||||
cond = uniop2rtlil(this, "$reduce_bool", 1, cond, false);
|
cond = uniop2rtlil(this, "$reduce_bool", 1, cond, false);
|
||||||
|
|
||||||
int width = max(val1.size(), val2.size());
|
int width = max(val1.size(), val2.size());
|
||||||
is_signed = children[1]->is_signed && children[2]->is_signed;
|
is_signed = children[1]->is_signed && children[2]->is_signed;
|
||||||
widthExtend(this, val1, width, is_signed);
|
widthExtend(this, val1, width, is_signed);
|
||||||
widthExtend(this, val2, width, is_signed);
|
widthExtend(this, val2, width, is_signed);
|
||||||
|
|
||||||
RTLIL::SigSpec sig = mux2rtlil(this, cond, val1, val2);
|
sig = mux2rtlil(this, cond, val1, val2);
|
||||||
|
}
|
||||||
|
|
||||||
if (sig.size() < width_hint)
|
if (sig.size() < width_hint)
|
||||||
sig.extend_u0(width_hint, sign_hint);
|
sig.extend_u0(width_hint, sign_hint);
|
||||||
|
|
|
@ -606,8 +606,10 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
|
||||||
int width_hint_left, width_hint_right;
|
int width_hint_left, width_hint_right;
|
||||||
bool sign_hint_left, sign_hint_right;
|
bool sign_hint_left, sign_hint_right;
|
||||||
bool found_real_left, found_real_right;
|
bool found_real_left, found_real_right;
|
||||||
children[1]->detectSignWidth(width_hint_left, sign_hint_left, &found_real_left);
|
children[1]->detectSignWidth(width_hint_left, sign_hint_left, &found_real_left,
|
||||||
children[2]->detectSignWidth(width_hint_right, sign_hint_right, &found_real_right);
|
children[0]->type == AST_CONSTANT && !children[0]->asBool() /* can_fail */);
|
||||||
|
children[2]->detectSignWidth(width_hint_right, sign_hint_right, &found_real_right,
|
||||||
|
children[0]->type == AST_CONSTANT && children[0]->asBool() /* can_fail */);
|
||||||
if (found_real_left || found_real_right) {
|
if (found_real_left || found_real_right) {
|
||||||
child_1_is_self_determined = true;
|
child_1_is_self_determined = true;
|
||||||
child_2_is_self_determined = true;
|
child_2_is_self_determined = true;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue