From a5cc905184f3a8112063742a13653a8be148a51b Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Fri, 7 Nov 2025 15:52:24 +1300 Subject: [PATCH 1/3] simplify.cc: Fix unsized const in params --- frontends/ast/simplify.cc | 10 +++++++--- tests/verilog/unbased_unsized.sv | 9 +++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 97abf7452..330e9ef12 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -2231,9 +2231,13 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin } if (children[0]->type == AST_CONSTANT) { if (width != int(children[0]->bits.size())) { - RTLIL::SigSpec sig(children[0]->bits); - sig.extend_u0(width, children[0]->is_signed); - children[0] = mkconst_bits(location, sig.as_const().to_bits(), is_signed); + RTLIL::Const val; + if (children[0]->is_unsized) { + val = children[0]->bitsAsUnsizedConst(width); + } else { + val = children[0]->bitsAsConst(width); + } + children[0] = mkconst_bits(location, val.to_bits(), is_signed); fixup_hierarchy_flags(); } children[0]->is_signed = is_signed; diff --git a/tests/verilog/unbased_unsized.sv b/tests/verilog/unbased_unsized.sv index 1d0c5a72c..af932cb74 100644 --- a/tests/verilog/unbased_unsized.sv +++ b/tests/verilog/unbased_unsized.sv @@ -6,6 +6,11 @@ module pass_through( endmodule module top; + localparam logic [63:0] + l01 = '0, + l02 = '1, + l03 = 'x, + l04 = 'z; logic [63:0] o01, o02, o03, o04, o05, o06, o07, o08, @@ -36,5 +41,9 @@ module top; assert (o10 === {64 {1'b1}}); assert (o11 === {64 {1'bx}}); assert (o12 === {64 {1'bz}}); + assert (l01 === {64 {1'b0}}); + assert (l02 === {64 {1'b1}}); + assert (l03 === {64 {1'bx}}); + assert (l04 === {64 {1'bz}}); end endmodule From e4c5900acd5caeaaea6f4e3983fe3f2ad6ba0495 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Fri, 7 Nov 2025 17:13:12 +1300 Subject: [PATCH 2/3] tests/verilog: Unsized params in cell Non-zero case fails with `read_verilog`, but passes with `verific` and `read_slang`. --- tests/verilog/unbased_unsized.sv | 16 ++++++++++++++++ tests/verilog/unbased_unsized.ys | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/tests/verilog/unbased_unsized.sv b/tests/verilog/unbased_unsized.sv index af932cb74..62f7d41ff 100644 --- a/tests/verilog/unbased_unsized.sv +++ b/tests/verilog/unbased_unsized.sv @@ -5,6 +5,14 @@ module pass_through( assign out = inp; endmodule +module set_param #( + parameter logic [63:0] VALUE +) ( + output logic [63:0] out +); + assign out = VALUE; +endmodule + module top; localparam logic [63:0] l01 = '0, @@ -28,6 +36,10 @@ module top; pass_through pt10('1, o10); pass_through pt11('x, o11); pass_through pt12('z, o12); + set_param #('0) sp13(o13); + set_param #('1) sp14(o14); + set_param #('x) sp15(o15); + set_param #('z) sp16(o16); always @* begin assert (o01 === {64 {1'b0}}); assert (o02 === {64 {1'b1}}); @@ -45,5 +57,9 @@ module top; assert (l02 === {64 {1'b1}}); assert (l03 === {64 {1'bx}}); assert (l04 === {64 {1'bz}}); + assert (o13 === {64 {1'b0}}); + assert (o14 === {64 {1'b1}}); + assert (o15 === {64 {1'bx}}); + assert (o16 === {64 {1'bz}}); end endmodule diff --git a/tests/verilog/unbased_unsized.ys b/tests/verilog/unbased_unsized.ys index 3290650d5..851866140 100644 --- a/tests/verilog/unbased_unsized.ys +++ b/tests/verilog/unbased_unsized.ys @@ -1,5 +1,5 @@ read_verilog -sv unbased_unsized.sv -hierarchy +hierarchy -top top proc flatten opt -full From 7302bf9a66b5b7635403cc4f59575b0e2899d414 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Fri, 7 Nov 2025 17:45:07 +1300 Subject: [PATCH 3/3] Add CONST_FLAG_UNSIZED In order to support unsized constants being used as parameters, the `const` struct needs to know if it is unsized (so that the parameter can be used to set the size). Add unsized flag to param value serialization and rtlil back-/front-end. Add cell params to `tests/rtlil/everything.v`. --- backends/rtlil/rtlil_backend.cc | 7 +++++-- frontends/ast/ast.cc | 9 +++++++-- frontends/rtlil/rtlil_frontend.cc | 5 +++++ kernel/rtlil.h | 9 +++++---- tests/rtlil/everything.v | 17 +++++++++++++++++ 5 files changed, 39 insertions(+), 8 deletions(-) diff --git a/backends/rtlil/rtlil_backend.cc b/backends/rtlil/rtlil_backend.cc index d607be837..63f64d12d 100644 --- a/backends/rtlil/rtlil_backend.cc +++ b/backends/rtlil/rtlil_backend.cc @@ -61,7 +61,9 @@ void RTLIL_BACKEND::dump_const(std::ostream &f, const RTLIL::Const &data, int wi return; } } - f << stringf("%d'", width); + if ((data.flags & RTLIL::CONST_FLAG_UNSIZED) == 0) { + f << stringf("%d'", width); + } if (data.flags & RTLIL::CONST_FLAG_SIGNED) { f << stringf("s"); } @@ -172,9 +174,10 @@ void RTLIL_BACKEND::dump_cell(std::ostream &f, std::string indent, const RTLIL:: dump_attributes(f, indent, cell); f << stringf("%s" "cell %s %s\n", indent, cell->type, cell->name); for (const auto& [name, param] : reversed(cell->parameters)) { - f << stringf("%s parameter%s%s %s ", indent, + f << stringf("%s parameter%s%s%s %s ", indent, (param.flags & RTLIL::CONST_FLAG_SIGNED) != 0 ? " signed" : "", (param.flags & RTLIL::CONST_FLAG_REAL) != 0 ? " real" : "", + (param.flags & RTLIL::CONST_FLAG_UNSIZED) != 0 ? " unsized" : "", name); dump_const(f, param); f << stringf("\n"); diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 4a16abee9..984c4294c 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -993,6 +993,8 @@ RTLIL::Const AstNode::asParaConst() const RTLIL::Const val = asAttrConst(); if (is_signed) val.flags |= RTLIL::CONST_FLAG_SIGNED; + if (is_unsized) + val.flags |= RTLIL::CONST_FLAG_UNSIZED; return val; } @@ -1766,7 +1768,10 @@ static std::string serialize_param_value(const RTLIL::Const &val) { res.push_back('s'); if (val.flags & RTLIL::ConstFlags::CONST_FLAG_REAL) res.push_back('r'); - res += stringf("%d", GetSize(val)); + if (val.flags & RTLIL::ConstFlags::CONST_FLAG_UNSIZED) + res.push_back('u'); + else + res += stringf("%d", GetSize(val)); res.push_back('\''); res.append(val.as_string("?")); return res; @@ -1860,7 +1865,7 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dictsecond.flags & RTLIL::CONST_FLAG_STRING) != 0) child->children[0] = AstNode::mkconst_str(loc, it->second.decode_string()); else - child->children[0] = AstNode::mkconst_bits(loc, it->second.to_bits(), (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0); + child->children[0] = AstNode::mkconst_bits(loc, it->second.to_bits(), (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0, (it->second.flags & RTLIL::CONST_FLAG_UNSIZED) != 0); rewritten.insert(it->first); } diff --git a/frontends/rtlil/rtlil_frontend.cc b/frontends/rtlil/rtlil_frontend.cc index 04d01fc93..271962725 100644 --- a/frontends/rtlil/rtlil_frontend.cc +++ b/frontends/rtlil/rtlil_frontend.cc @@ -567,10 +567,13 @@ struct RTLILFrontendWorker { if (try_parse_keyword("parameter")) { bool is_signed = false; bool is_real = false; + bool is_unsized = false; if (try_parse_keyword("signed")) { is_signed = true; } else if (try_parse_keyword("real")) { is_real = true; + } else if (try_parse_keyword("unsized")) { + is_unsized = true; } RTLIL::IdString param_name = parse_id(); RTLIL::Const val = parse_const(); @@ -578,6 +581,8 @@ struct RTLILFrontendWorker { val.flags |= RTLIL::CONST_FLAG_SIGNED; if (is_real) val.flags |= RTLIL::CONST_FLAG_REAL; + if (is_unsized) + val.flags |= RTLIL::CONST_FLAG_UNSIZED; cell->parameters.insert({std::move(param_name), std::move(val)}); expect_eol(); } else if (try_parse_keyword("connect")) { diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 7e699b365..85ae70ef4 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -53,10 +53,11 @@ namespace RTLIL // Semantic metadata - how can this constant be interpreted? // Values may be generally non-exclusive enum ConstFlags : unsigned char { - CONST_FLAG_NONE = 0, - CONST_FLAG_STRING = 1, - CONST_FLAG_SIGNED = 2, // only used for parameters - CONST_FLAG_REAL = 4 // only used for parameters + CONST_FLAG_NONE = 0, + CONST_FLAG_STRING = 1, + CONST_FLAG_SIGNED = 2, // only used for parameters + CONST_FLAG_REAL = 4, // only used for parameters + CONST_FLAG_UNSIZED = 8, // only used for parameters }; enum SelectPartials : unsigned char { diff --git a/tests/rtlil/everything.v b/tests/rtlil/everything.v index 666d630c2..c4f8c348a 100644 --- a/tests/rtlil/everything.v +++ b/tests/rtlil/everything.v @@ -38,3 +38,20 @@ module foo( assign b = bb; assign y = a + bb; endmodule + +module set_param #( + parameter [3:0] VALUE = 1'bx +) ( + output logic [3:0] out +); + assign out = VALUE; +endmodule + +module use_param ( + output logic [3:0] a, b, c, d +); + set_param #($signed(1)) spa (a); + set_param #('1) spb (b); + set_param #(1.1) spc (c); + set_param #(1'b1) spd (d); +endmodule