diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index a99f0803e37..1a7dc6b41e8 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -615,6 +615,15 @@ int RTLIL::Const::as_int_saturating(bool is_signed) const return as_int(is_signed); } +void RTLIL::Const::tag_bare_integer_const(const std::string &value) +{ + if (value.empty() || value.find('\'') != std::string::npos) + return; + size_t start = (value[0] == '-' || value[0] == '+') ? 1 : 0; + if (start < value.size() && std::all_of(value.begin() + start, value.end(), ::isdigit)) + flags |= RTLIL::CONST_FLAG_SIGNED; +} + int RTLIL::Const::get_min_size(bool is_signed) const { if (empty()) return 0; diff --git a/kernel/rtlil.h b/kernel/rtlil.h index b32f9ea76be..e55caf35a64 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1091,6 +1091,8 @@ struct RTLIL::Const // over/underflow, otherwise the max/min value for int depending on the sign. int as_int_saturating(bool is_signed = false) const; + void tag_bare_integer_const(const std::string &value); + std::string as_string(const char* any = "-") const; static Const from_string(const std::string &str); std::vector to_bits() const; diff --git a/passes/cmds/setattr.cc b/passes/cmds/setattr.cc index 25d8fd34c45..ef9bd0d3437 100644 --- a/passes/cmds/setattr.cc +++ b/passes/cmds/setattr.cc @@ -41,6 +41,7 @@ struct setunset_t if (!RTLIL::SigSpec::parse(sig_value, nullptr, set_value)) log_cmd_error("Can't decode value '%s'!\n", set_value); value = sig_value.as_const(); + value.tag_bare_integer_const(set_value); } } }; diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc index 416997bee53..34cedfd3435 100644 --- a/passes/hierarchy/hierarchy.cc +++ b/passes/hierarchy/hierarchy.cc @@ -985,7 +985,9 @@ struct HierarchyPass : public Pass { SigSpec sig_value; if (!RTLIL::SigSpec::parse(sig_value, NULL, para.second)) log_cmd_error("Can't decode value '%s'!\n", para.second); - top_parameters[RTLIL::escape_id(para.first)] = sig_value.as_const(); + RTLIL::Const c = sig_value.as_const(); + c.tag_bare_integer_const(para.second); + top_parameters[RTLIL::escape_id(para.first)] = c; } } @@ -1073,7 +1075,9 @@ struct HierarchyPass : public Pass { SigSpec sig_value; if (!RTLIL::SigSpec::parse(sig_value, NULL, para.second)) log_cmd_error("Can't decode value '%s'!\n", para.second); - top_parameters[RTLIL::escape_id(para.first)] = sig_value.as_const(); + RTLIL::Const c = sig_value.as_const(); + c.tag_bare_integer_const(para.second); + top_parameters[RTLIL::escape_id(para.first)] = c; } top_mod = design->module(top_mod->derive(design, top_parameters)); diff --git a/tests/verilog/issue5745.ys b/tests/verilog/issue5745.ys new file mode 100644 index 00000000000..938ead63ae8 --- /dev/null +++ b/tests/verilog/issue5745.ys @@ -0,0 +1,18 @@ +# Issue #5745: chparam values are unsigned when using read_verilog frontend +# +# When chparam overrides a parameter value, the signed attribute is lost, +# causing signed comparisons to silently use unsigned logic. +# +# m = -32 (signed 9-bit), p2 = 11. Correct signed semantics: -32 < 11, so k = 1. +# Bug: chparam strips the signed attribute from p2. The $lt cell gets A_SIGNED=0, +# B_SIGNED=0, so the comparison treats m as unsigned (480 > 11), giving k = 0. + +read_verilog <