mirror of
https://github.com/verilator/verilator.git
synced 2026-10-05 17:43:31 +02:00
@@ -162,6 +162,18 @@ Hierarchy blocks have some limitations, including:
|
||||
|
||||
- Delays are not allowed in hierarchy blocks.
|
||||
|
||||
- Setting type parameters of a hierarchy block is unsupported.
|
||||
|
||||
- A ``defparam`` setting a parameter inside a hierarchy block is
|
||||
unsupported.
|
||||
|
||||
- String parameter values of a hierarchy block containing a newline, a
|
||||
double quote, ``/*``, or whitespace followed by ``//`` are unsupported.
|
||||
|
||||
- Values that are equal but differ in width or signedness (``5`` and
|
||||
``8'd5``), including relative to the default value, are unsupported for a
|
||||
hierarchy block parameter declared without a data type.
|
||||
|
||||
But, the following usage is supported:
|
||||
|
||||
- Nested hierarchy blocks. A hierarchy block may instantiate other
|
||||
|
||||
@@ -1253,6 +1253,10 @@ public:
|
||||
int instrCount() const override { return widthInstrs(); }
|
||||
bool isEqAllOnes() const { return num().isEqAllOnes(width()); }
|
||||
bool isEqAllOnesV() const { return num().isEqAllOnes(widthMinV()); }
|
||||
// Whether a parameter declared without a data type takes the same type from this value
|
||||
// as from 'samep': both real, both string, or both integral with the same width and
|
||||
// signedness. Unlike AstNodeDType::similarDType, ignores whether two-state or four-state.
|
||||
bool sameValueType(const AstConst* samep) const;
|
||||
// Parse string and create appropriate type of AstConst.
|
||||
// May return nullptr on parse failure.
|
||||
static AstConst* parseParamLiteral(FileLine* fl, const string& literal);
|
||||
|
||||
@@ -1183,6 +1183,12 @@ AstConst* AstConst::parseParamLiteral(FileLine* fl, const string& literal) {
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
bool AstConst::sameValueType(const AstConst* samep) const {
|
||||
if (num().isDouble() != samep->num().isDouble()) return false;
|
||||
if (num().isString() != samep->num().isString()) return false;
|
||||
// Constant folding can leave the signedness on the dtype, not the V3Number
|
||||
return num().isOpaque() || (width() == samep->width() && isSigned() == samep->isSigned());
|
||||
}
|
||||
AstConst::~AstConst() {
|
||||
// Only rare constants carry originating parameter-name metadata. For all other AstConst nodes,
|
||||
// the V3Number bit keeps this destructor from touching AstNetlist's side table. When the bit
|
||||
|
||||
+18
-1
@@ -95,6 +95,7 @@
|
||||
#include "V3Stats.h"
|
||||
#include "V3String.h"
|
||||
|
||||
#include <cctype>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
@@ -125,6 +126,19 @@ static void V3HierWriteCommonInputs(const V3HierBlock* hblockp, std::ostream* of
|
||||
|
||||
//######################################################################
|
||||
|
||||
bool V3HierBlock::stringParamPassable(const string& value) {
|
||||
// stringifyParams writes string values in double quotes into the arguments file, which
|
||||
// V3Options::parseOptsFile reads by lines, removing '/*' comments, and '//' comments after
|
||||
// whitespace, before splitting the quoted arguments. AstConst::parseParamLiteral for -G,
|
||||
// and V3HierarchicalBlockOption, then end each value at the next double quote.
|
||||
if (value.find_first_of("\n\"") != string::npos) return false;
|
||||
if (value.find("/*") != string::npos) return false;
|
||||
for (size_t pos = value.find("//"); pos != string::npos; pos = value.find("//", pos + 1)) {
|
||||
if (pos > 0 && std::isspace(static_cast<unsigned char>(value[pos - 1]))) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
V3HierBlock::StrGParams V3HierBlock::stringifyParams(const std::vector<AstVar*>& gparams,
|
||||
bool forGOption) {
|
||||
StrGParams strParams;
|
||||
@@ -148,7 +162,10 @@ V3HierBlock::StrGParams V3HierBlock::stringifyParams(const std::vector<AstVar*>&
|
||||
if (!forGOption) s = VString::quoteBackslash(s);
|
||||
s = VString::quoteStringLiteralForShell(s);
|
||||
} else { // Either signed or unsigned integer.
|
||||
s = constp->num().ascii(true, true);
|
||||
// Constant folding can leave the signedness on the dtype, not the V3Number.
|
||||
V3Number num{constp->num()};
|
||||
num.isSigned(constp->isSigned());
|
||||
s = num.ascii(true, true);
|
||||
s = VString::quoteAny(s, '\'', '\\');
|
||||
}
|
||||
strParams.emplace_back(gparam->name(), s);
|
||||
|
||||
@@ -85,6 +85,9 @@ public:
|
||||
|
||||
const AstModule* modp() const { return m_modp; }
|
||||
|
||||
// Whether a string parameter value can be passed to a hierarchical block's Verilation
|
||||
static bool stringParamPassable(const string& value) VL_PURE;
|
||||
|
||||
// For emitting Makefile and build definition JSON
|
||||
VStringList commandArgs(bool forMkJson) const VL_MT_DISABLED;
|
||||
VStringList hierBlockArgs() const VL_MT_DISABLED;
|
||||
|
||||
+72
-6
@@ -57,6 +57,7 @@
|
||||
#include "V3Case.h"
|
||||
#include "V3Const.h"
|
||||
#include "V3EmitV.h"
|
||||
#include "V3HierBlock.h"
|
||||
#include "V3LinkDotIfaceCapture.h"
|
||||
#include "V3MemberMap.h"
|
||||
#include "V3Os.h"
|
||||
@@ -106,14 +107,16 @@ class ParameterizedHierBlocks final {
|
||||
std::map<const V3HierarchicalBlockOption*, ParamConstMap> m_hierParams;
|
||||
// Parameter variables of hierarchical blocks
|
||||
std::map<const std::string, GParamsMap> m_modParams;
|
||||
// Formals declared without a type, whose type is that of the assigned value
|
||||
std::set<const AstVar*> m_untypedParams;
|
||||
|
||||
// METHODS
|
||||
|
||||
public:
|
||||
ParameterizedHierBlocks(const V3HierBlockOptSet& hierOpts, AstNetlist* nodep)
|
||||
: m_hierSubRun{(!v3Global.opt.hierBlocks().empty() || v3Global.opt.hierChild())
|
||||
// Exclude consolidation
|
||||
&& !v3Global.opt.hierParamFile().empty()} {
|
||||
// A type parameter file only describes a child's own types; the final consolidation
|
||||
// run has none, but must still substitute the libraries it consumes.
|
||||
: m_hierSubRun{!v3Global.opt.hierBlocks().empty() || v3Global.opt.hierChild()} {
|
||||
for (const auto& hierOpt : hierOpts) {
|
||||
m_hierBlockOptsByOrigName.emplace(hierOpt.second.origName(), &hierOpt.second);
|
||||
const V3HierarchicalBlockOption::ParamStrMap& params = hierOpt.second.params();
|
||||
@@ -144,6 +147,12 @@ public:
|
||||
for (AstNode* stmtp = modp->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||
if (AstVar* const varp = VN_CAST(stmtp, Var)) {
|
||||
if (varp->isGParam()) defParamIt->second.emplace(varp->name(), varp);
|
||||
// Recorded before V3Param resolves the type from the assigned value.
|
||||
const AstBasicDType* const dtypep
|
||||
= VN_CAST(varp->childDTypep(), BasicDType);
|
||||
if (varp->isGParam() && dtypep && dtypep->implicit()) {
|
||||
m_untypedParams.emplace(varp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -161,6 +170,10 @@ public:
|
||||
= m_hierBlockOptsByOrigName.equal_range(origName);
|
||||
const auto paramsIt = m_modParams.find(origName);
|
||||
UASSERT_OBJ(paramsIt != m_modParams.end(), modp, origName << " must be registered");
|
||||
// An untyped parameter takes the type of its value, but libraries are distinguished
|
||||
// only by parameter values. This is a pin whose value equals that of a library or the
|
||||
// default, but whose type differs.
|
||||
const AstPin* typeMismatchPinp = nullptr;
|
||||
HierMapIt hierIt;
|
||||
for (hierIt = candidates.first; hierIt != candidates.second; ++hierIt) {
|
||||
bool found = true;
|
||||
@@ -175,10 +188,14 @@ public:
|
||||
"parameter for a hierarchical block must have been constified");
|
||||
const auto paramIt = paramsIt->second.find(modvarp->name());
|
||||
UASSERT_OBJ(paramIt != paramsIt->second.end(), modvarp, "must be registered");
|
||||
const bool untyped = m_untypedParams.count(paramIt->second);
|
||||
AstConst* const defValuep = VN_CAST(paramIt->second->valuep(), Const);
|
||||
if (defValuep && areSame(constp, defValuep)) {
|
||||
UINFO(5, "Setting default value of " << constp << " to " << modvarp);
|
||||
continue; // Skip this parameter because setting the same value
|
||||
if (!untyped || constp->sameValueType(defValuep)) {
|
||||
UINFO(5, "Setting default value of " << constp << " to " << modvarp);
|
||||
continue; // Skip this parameter because setting the same value
|
||||
}
|
||||
typeMismatchPinp = pinp;
|
||||
}
|
||||
const auto pIt = vlstd::as_const(params).find(modvarp->name());
|
||||
UINFO(5, "Comparing " << modvarp->name() << " " << constp);
|
||||
@@ -187,6 +204,11 @@ public:
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
if (untyped && !constp->sameValueType(pIt->second.get())) {
|
||||
typeMismatchPinp = pinp;
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
UINFO(5, "Matched " << modvarp->name() << " " << constp << " and "
|
||||
<< pIt->second.get());
|
||||
++paramIdx;
|
||||
@@ -194,6 +216,15 @@ public:
|
||||
}
|
||||
if (found && paramIdx == hierIt->second->params().size()) break;
|
||||
}
|
||||
if (hierIt == candidates.second && typeMismatchPinp) {
|
||||
typeMismatchPinp->v3warn(
|
||||
E_UNSUPPORTED, "Unsupported: Untyped parameter "
|
||||
<< typeMismatchPinp->modVarp()->prettyNameQ()
|
||||
<< " of hierarchical block " << AstNode::prettyNameQ(origName)
|
||||
<< " given equal values of different width or"
|
||||
" signedness");
|
||||
return nullptr;
|
||||
}
|
||||
UASSERT_OBJ(hierIt != candidates.second, firstPinp, "No --lib-create wrapper found");
|
||||
// parameter settings will be removed in the bottom of caller visitCell().
|
||||
const HierBlockModMap::const_iterator modIt
|
||||
@@ -306,6 +337,8 @@ class ParamProcessor final {
|
||||
using DefaultValueMap = std::map<std::string, AstNode*>;
|
||||
// Default parameter values of hierarchical blocks
|
||||
std::map<AstNodeModule*, DefaultValueMap> m_defaultParameterValues;
|
||||
// Module -> a defparam in it or below it, or nullptr (see nestedDefparamp)
|
||||
std::map<const AstNodeModule*, const AstPin*> m_nestedDefparamps;
|
||||
VNDeleter m_deleter; // Used to delay deletion of nodes
|
||||
// Class default type paramater dependencies
|
||||
std::vector<std::pair<AstParamTypeDType*, int>> m_classTypeParams;
|
||||
@@ -628,6 +661,23 @@ class ParamProcessor final {
|
||||
std::set<const AstNodeModule*> visited;
|
||||
return hasDescendantDefparams(modp, visited);
|
||||
}
|
||||
// Return a defparam in the module or below it. Unlike hasDescendantDefparams, also look
|
||||
// inside generate constructs. Memoized, so each module is searched once.
|
||||
const AstPin* nestedDefparamp(const AstNodeModule* modp) {
|
||||
const auto pair = m_nestedDefparamps.emplace(modp, nullptr);
|
||||
if (!pair.second) return pair.first->second; // Searched, or being searched
|
||||
const AstPin* foundp = nullptr;
|
||||
modp->exists([&](const AstCell* cellp) {
|
||||
for (const AstPin* pinp = cellp->paramsp(); pinp && !foundp;
|
||||
pinp = VN_AS(pinp->nextp(), Pin)) {
|
||||
if (!pinp->paramPath().empty()) foundp = pinp;
|
||||
}
|
||||
if (!foundp && cellp->modp()) foundp = nestedDefparamp(cellp->modp());
|
||||
return foundp != nullptr;
|
||||
});
|
||||
pair.first->second = foundp;
|
||||
return foundp;
|
||||
}
|
||||
// Check if parameter setting during instantiation is simple enough for hierarchical Verilation
|
||||
void checkSupportedParam(AstNodeModule* modp, AstPin* pinp) const {
|
||||
// InitArray is not supported because that can not be set via -G
|
||||
@@ -636,6 +686,12 @@ class ParamProcessor final {
|
||||
bool supported = false;
|
||||
if (const AstConst* const constp = VN_CAST(pinp->exprp(), Const)) {
|
||||
supported = !constp->isOpaque();
|
||||
if (constp->num().isString()
|
||||
&& !V3HierBlock::stringParamPassable(constp->num().toString())) {
|
||||
pinp->v3warn(E_UNSUPPORTED, "Unsupported: String value of hierarchical block"
|
||||
" parameter with newline, double quote, '/*',"
|
||||
" or whitespace before '//'");
|
||||
}
|
||||
}
|
||||
if (!supported) {
|
||||
pinp->v3error(
|
||||
@@ -643,6 +699,11 @@ class ParamProcessor final {
|
||||
<< " has hier_block metacomment, hierarchical Verilation"
|
||||
<< " supports only integer/floating point/string and type param parameters");
|
||||
}
|
||||
} else if (const AstParamTypeDType* const typep = pinp->modPTypep()) {
|
||||
// Libraries are found by comparing values only
|
||||
pinp->v3warn(E_UNSUPPORTED, "Unsupported: Setting type parameter "
|
||||
<< typep->prettyNameQ() << " of hierarchical block "
|
||||
<< AstNode::prettyNameQ(modp->origName()));
|
||||
}
|
||||
}
|
||||
bool moduleExists(const string& modName) const {
|
||||
@@ -675,6 +736,11 @@ class ParamProcessor final {
|
||||
const auto pair = m_defaultParameterValues.emplace(
|
||||
std::piecewise_construct, std::forward_as_tuple(modp), std::forward_as_tuple());
|
||||
if (pair.second) { // Not cached yet, so check parameters
|
||||
// A separately compiled library cannot receive defparams aimed into its body
|
||||
if (const AstPin* const defparamp = nestedDefparamp(modp)) {
|
||||
defparamp->v3warn(E_UNSUPPORTED, "Unsupported: defparam inside hierarchical block "
|
||||
<< AstNode::prettyNameQ(modp->origName()));
|
||||
}
|
||||
// Using map with key=string so that we can scan it in deterministic order
|
||||
DefaultValueMap params;
|
||||
for (AstNode* stmtp = modp->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||
@@ -2010,7 +2076,7 @@ class ParamProcessor final {
|
||||
if (m_hierBlocks.hierSubRun() && m_hierBlocks.isHierBlock(srcModp->origName())) {
|
||||
AstNodeModule* const paramedModp
|
||||
= m_hierBlocks.findByParams(srcModp->origName(), paramsp, m_modp);
|
||||
UASSERT_OBJ(paramedModp, nodep, "Failed to find sub-module for hierarchical block");
|
||||
if (!paramedModp) return nullptr; // Unsupported, already reported
|
||||
paramedModp->dead(false);
|
||||
// We need to relink the pins to the new module
|
||||
relinkPinsByName(pinsp, paramedModp);
|
||||
|
||||
@@ -63,10 +63,14 @@ module t #(
|
||||
`ifdef PROTLIB_TOP
|
||||
secret i_secred(.clk(clk));
|
||||
`else
|
||||
// Outputs of hierarchical blocks depend on all their inputs, so this registered ring
|
||||
// through the blocks appears combinational
|
||||
/* verilator lint_off UNOPTFLAT */
|
||||
wire [7:0] out0;
|
||||
wire [7:0] out1;
|
||||
wire [7:0] out2;
|
||||
wire [7:0] out3;
|
||||
/* verilator lint_on UNOPTFLAT */
|
||||
wire [7:0] out3_2;
|
||||
wire [7:0] out5;
|
||||
wire [7:0] out6;
|
||||
|
||||
@@ -3,6 +3,11 @@
|
||||
21 | sub0 #(UNPACKED) i_sub0 (
|
||||
| ^~~~~~~~
|
||||
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
|
||||
%Error-UNSUPPORTED: t/t_hier_block0_bad.v:27:8: Unsupported: Setting type parameter 'T' of hierarchical block 'sub1'
|
||||
: ... note: In instance 't'
|
||||
27 | .T(logic [7:0])
|
||||
| ^
|
||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
||||
%Error: t/t_hier_block0_bad.v:77:39: Cannot access non-port symbols inside hierarchical block
|
||||
: ... note: In instance 't.i_sub0'
|
||||
77 | $display("%m: i_sub.x: %d", i_sub.x);
|
||||
|
||||
@@ -13,15 +13,15 @@ module t (
|
||||
input clk
|
||||
);
|
||||
logic [7:0] c;
|
||||
logic [6:0] c_param;
|
||||
logic [7:0] c_param;
|
||||
int cycles = 0;
|
||||
|
||||
blk u (
|
||||
.clk(clk),
|
||||
.cnt_o(c)
|
||||
);
|
||||
// Type parameter T keeps its default from my_pkg; setting it is unsupported
|
||||
blk_param #(
|
||||
.T(logic [6:0]),
|
||||
.STEP(3)
|
||||
) u_param (
|
||||
.clk(clk),
|
||||
@@ -31,10 +31,10 @@ module t (
|
||||
always @(negedge clk) begin
|
||||
cycles = cycles + 1;
|
||||
`checkd(c, 8'(cycles));
|
||||
`checkd(c_param, 7'(cycles * 3));
|
||||
`checkd(c_param, 8'(cycles * 3));
|
||||
if (cycles == 10) begin
|
||||
`checkd(c, 8'd10);
|
||||
`checkd(c_param, 7'd30);
|
||||
`checkd(c_param, 8'd30);
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of either the GNU Lesser General Public License Version 3
|
||||
# or the Perl Artistic License Version 2.0.
|
||||
# SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt')
|
||||
|
||||
# Otherwise a rerun skips the unchanged plan, and so the failing final Verilation
|
||||
test.clean_objs()
|
||||
|
||||
# Reported when the final Verilation, run by make, looks up the libraries
|
||||
test.compile(verilator_flags2=['--hierarchical'], fails='any')
|
||||
|
||||
for line in (19, 21):
|
||||
test.file_grep(
|
||||
test.compile_log_filename,
|
||||
r"%Error-UNSUPPORTED: t/t_hier_block_param_kind_unsup.v:" + str(line) +
|
||||
r":10: Unsupported: Untyped parameter 'P' of hierarchical block 'mid' given equal values of different width or signedness"
|
||||
)
|
||||
|
||||
test.passes()
|
||||
@@ -0,0 +1,38 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// verilog_format: off
|
||||
`define stop $stop
|
||||
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
|
||||
// verilog_format: on
|
||||
|
||||
module t (
|
||||
input clk
|
||||
);
|
||||
// The untyped parameter is 32 bits wide for 5, but 8 bits for 8'd5, so they need different
|
||||
// libraries, but libraries are distinguished by parameter values only
|
||||
int width0, width1, width2;
|
||||
mid #(.P(5)) m0 (.width(width0));
|
||||
mid #(.P(8'd5)) m1 (.width(width1));
|
||||
// Likewise relative to the default value
|
||||
mid #(.P(8'd0)) m2 (.width(width2));
|
||||
always @(posedge clk) begin
|
||||
`checkd(width0, 32);
|
||||
`checkd(width1, 8);
|
||||
`checkd(width2, 8);
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
||||
module mid #(
|
||||
parameter P = 0
|
||||
) (
|
||||
output int width
|
||||
);
|
||||
/*verilator hier_block*/
|
||||
assign width = $bits(P);
|
||||
endmodule
|
||||
+6
-3
@@ -4,14 +4,17 @@
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of either the GNU Lesser General Public License Version 3
|
||||
# or the Perl Artistic License Version 2.0.
|
||||
# SPDX-FileCopyrightText: 2024 Wilson Snyder
|
||||
# SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
test.scenarios('vlt_all')
|
||||
|
||||
test.compile(verilator_flags2=['--hierarchical'])
|
||||
threads = 2 if test.vltmt else 1
|
||||
|
||||
test.compile(verilator_flags2=['--hierarchical', '-DROOT_THREADS=' + str(threads)],
|
||||
threads=threads)
|
||||
|
||||
test.execute()
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Parameterized hierarchical blocks must be replaced by their libraries in the final
|
||||
// compilation (#7009), each by the library built for its parameter values.
|
||||
|
||||
// verilog_format: off
|
||||
`define stop $stop
|
||||
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
|
||||
// verilog_format: on
|
||||
|
||||
module t (
|
||||
input clk
|
||||
);
|
||||
// Library models: a0, a1, a2, m0 and the acc instance inside it, s0, and s1
|
||||
localparam int LIBRARY_MODELS = 7;
|
||||
int cyc = 0;
|
||||
longint data[6], out[6];
|
||||
longint expected[6] = '{default: 0};
|
||||
for (genvar i = 0; i < 6; ++i) begin : stim
|
||||
assign data[i] = longint'(cyc * (i + 3) + i * 7);
|
||||
end
|
||||
|
||||
// K=3 is shared by two instances with independent state
|
||||
acc #(
|
||||
.K(3)
|
||||
) a0 (
|
||||
.clk,
|
||||
.data(data[0]),
|
||||
.out(out[0])
|
||||
);
|
||||
acc #(
|
||||
.K(3)
|
||||
) a1 (
|
||||
.clk,
|
||||
.data(data[1]),
|
||||
.out(out[1])
|
||||
);
|
||||
// The untyped parameter is a signed -1, which must reach the library
|
||||
acc #(
|
||||
.K(-1)
|
||||
) a2 (
|
||||
.clk,
|
||||
.data(data[2]),
|
||||
.out(out[2])
|
||||
);
|
||||
// Also the acc instance inside is a library
|
||||
mid #(
|
||||
.P(5)
|
||||
) m0 (
|
||||
.clk,
|
||||
.data(data[3]),
|
||||
.out(out[3])
|
||||
);
|
||||
// Strings that the generated child arguments carry
|
||||
str_blk #(
|
||||
.S("p q,r")
|
||||
) s0 (
|
||||
.clk,
|
||||
.data(data[4]),
|
||||
.out(out[4])
|
||||
);
|
||||
str_blk #(
|
||||
.S("a//b\\c */")
|
||||
) s1 (
|
||||
.clk,
|
||||
.data(data[5]),
|
||||
.out(out[5])
|
||||
);
|
||||
|
||||
function automatic longint str_hash(string s);
|
||||
str_hash = 0;
|
||||
for (int i = 0; i < s.len(); ++i) str_hash = str_hash * 31 + longint'(s[i]);
|
||||
endfunction
|
||||
|
||||
always @(posedge clk) begin
|
||||
// Each library adds its value and the parameter's width, so a wrong library changes the sum
|
||||
expected[0] <= expected[0] + data[0] + 3 + 32;
|
||||
expected[1] <= expected[1] + data[1] + 3 + 32;
|
||||
expected[2] <= expected[2] + data[2] - 1 + 32;
|
||||
expected[3] <= expected[3] + data[3] + 5 + 32;
|
||||
expected[4] <= expected[4] + data[4] + str_hash("p q,r");
|
||||
expected[5] <= expected[5] + data[5] + str_hash("a//b\\c */");
|
||||
end
|
||||
always @(negedge clk) begin
|
||||
foreach (out[i]) `checkd(out[i], expected[i]);
|
||||
cyc <= cyc + 1;
|
||||
if (cyc == 60) begin
|
||||
`ifdef VERILATOR
|
||||
// Every block instance is a library model, with its own thread
|
||||
`checkd($c32("Verilated::threadContextp()->threadsInModels()"),
|
||||
`ROOT_THREADS + LIBRARY_MODELS);
|
||||
`endif
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
|
||||
module acc #(
|
||||
parameter K = 0
|
||||
) (
|
||||
input clk,
|
||||
input longint data,
|
||||
output longint out
|
||||
);
|
||||
/*verilator hier_block*/
|
||||
longint state = 0;
|
||||
always @(posedge clk) state <= state + data + longint'(K) + longint'($bits(K));
|
||||
assign out = state;
|
||||
endmodule
|
||||
|
||||
module mid #(
|
||||
parameter P = 0
|
||||
) (
|
||||
input clk,
|
||||
input longint data,
|
||||
output longint out
|
||||
);
|
||||
/*verilator hier_block*/
|
||||
acc #(
|
||||
.K(P)
|
||||
) inner (
|
||||
.clk,
|
||||
.data,
|
||||
.out
|
||||
);
|
||||
endmodule
|
||||
|
||||
module str_blk #(
|
||||
parameter string S = "x"
|
||||
) (
|
||||
input clk,
|
||||
input longint data,
|
||||
output longint out
|
||||
);
|
||||
/*verilator hier_block*/
|
||||
function automatic longint str_hash();
|
||||
str_hash = 0;
|
||||
for (int i = 0; i < S.len(); ++i) str_hash = str_hash * 31 + longint'(S[i]);
|
||||
endfunction
|
||||
longint state = 0;
|
||||
always @(posedge clk) state <= state + data + str_hash();
|
||||
assign out = state;
|
||||
endmodule
|
||||
@@ -0,0 +1,53 @@
|
||||
%Error-UNSUPPORTED: t/t_hier_block_param_lib_unsup.v:10:12: Unsupported: Setting type parameter 'T' of hierarchical block 'typed'
|
||||
: ... note: In instance 't'
|
||||
10 | typed #(.T(logic signed [6:0])) t0 ();
|
||||
| ^
|
||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
||||
%Error-UNSUPPORTED: t/t_hier_block_param_lib_unsup.v:11:12: Unsupported: Setting type parameter 'T' of hierarchical block 'typed'
|
||||
: ... note: In instance 't'
|
||||
11 | typed #(.T(word_t)) t1 ();
|
||||
| ^
|
||||
%Error-UNSUPPORTED: t/t_hier_block_param_lib_unsup.v:13:8: Unsupported: Setting type parameter 'TIN' of hierarchical block 'typed2'
|
||||
: ... note: In instance 't'
|
||||
13 | .TIN(logic [3:0]),
|
||||
| ^~~
|
||||
%Error-UNSUPPORTED: t/t_hier_block_param_lib_unsup.v:14:8: Unsupported: Setting type parameter 'TOUT' of hierarchical block 'typed2'
|
||||
: ... note: In instance 't'
|
||||
14 | .TOUT(logic [7:0])
|
||||
| ^~~~
|
||||
%Error-UNSUPPORTED: t/t_hier_block_param_lib_unsup.v:16:14: Unsupported: Setting type parameter 'T' of hierarchical block 'nonansi'
|
||||
: ... note: In instance 't'
|
||||
16 | nonansi #(.T(logic [1:0])) t3 ();
|
||||
| ^
|
||||
%Error-UNSUPPORTED: t/t_hier_block_param_lib_unsup.v:23:14: Unsupported: String value of hierarchical block parameter with newline, double quote, '/*', or whitespace before '//'
|
||||
: ... note: In instance 't'
|
||||
23 | str_blk #(.S(S0)) s0 ();
|
||||
| ^
|
||||
%Error-UNSUPPORTED: t/t_hier_block_param_lib_unsup.v:24:14: Unsupported: String value of hierarchical block parameter with newline, double quote, '/*', or whitespace before '//'
|
||||
: ... note: In instance 't'
|
||||
24 | str_blk #(.S(S1)) s1 ();
|
||||
| ^
|
||||
%Error-UNSUPPORTED: t/t_hier_block_param_lib_unsup.v:25:14: Unsupported: String value of hierarchical block parameter with newline, double quote, '/*', or whitespace before '//'
|
||||
: ... note: In instance 't'
|
||||
25 | str_blk #(.S(S2)) s2 ();
|
||||
| ^
|
||||
%Error-UNSUPPORTED: t/t_hier_block_param_lib_unsup.v:26:14: Unsupported: String value of hierarchical block parameter with newline, double quote, '/*', or whitespace before '//'
|
||||
: ... note: In instance 't'
|
||||
26 | str_blk #(.S(S3)) s3 ();
|
||||
| ^
|
||||
%Error-UNSUPPORTED: t/t_hier_block_param_lib_unsup.v:29:23: Unsupported: defparam inside hierarchical block 'fixed'
|
||||
: ... note: In instance 't.f0'
|
||||
29 | defparam f0.child.N = 2;
|
||||
| ^
|
||||
%Error-UNSUPPORTED: t/t_hier_block_param_lib_unsup.v:83:20: Unsupported: defparam inside hierarchical block 'nested'
|
||||
83 | defparam child.N = 3;
|
||||
| ^
|
||||
%Error-UNSUPPORTED: t/t_hier_block_param_lib_unsup.v:91:22: Unsupported: defparam inside hierarchical block 'generated'
|
||||
: ... note: In instance 't.g0'
|
||||
91 | defparam child.N = 4;
|
||||
| ^
|
||||
%Error-UNSUPPORTED: t/t_hier_block_param_lib_unsup.v:61:12: Unsupported: Setting type parameter 'T' of hierarchical block 'typed'
|
||||
: ... note: In instance 't.o0'
|
||||
61 | typed #(.T(T)) inner ();
|
||||
| ^
|
||||
%Error: Exiting due to
|
||||
+3
-5
@@ -4,15 +4,13 @@
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of either the GNU Lesser General Public License Version 3
|
||||
# or the Perl Artistic License Version 2.0.
|
||||
# SPDX-FileCopyrightText: 2024 Wilson Snyder
|
||||
# SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
test.scenarios('vlt')
|
||||
|
||||
test.compile(verilator_flags2=['--hierarchical'])
|
||||
|
||||
test.execute()
|
||||
test.lint(verilator_flags2=['--hierarchical'], fails=True, expect_filename=test.golden_filename)
|
||||
|
||||
test.passes()
|
||||
@@ -0,0 +1,98 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t;
|
||||
// Libraries are found by comparing parameter values, not types
|
||||
typedef logic [5:0] word_t;
|
||||
typed #(.T(logic signed [6:0])) t0 ();
|
||||
typed #(.T(word_t)) t1 ();
|
||||
typed2 #(
|
||||
.TIN(logic [3:0]),
|
||||
.TOUT(logic [7:0])
|
||||
) t2 ();
|
||||
nonansi #(.T(logic [1:0])) t3 ();
|
||||
outer o0 ();
|
||||
// The generated child arguments cannot carry these strings
|
||||
localparam string S0 = "p/*q*/r";
|
||||
localparam string S1 = "p //q";
|
||||
localparam string S2 = "p\"q";
|
||||
localparam string S3 = "p\nq";
|
||||
str_blk #(.S(S0)) s0 ();
|
||||
str_blk #(.S(S1)) s1 ();
|
||||
str_blk #(.S(S2)) s2 ();
|
||||
str_blk #(.S(S3)) s3 ();
|
||||
// A library cannot receive defparams
|
||||
fixed f0 ();
|
||||
defparam f0.child.N = 2;
|
||||
nested n0 ();
|
||||
generated g0 ();
|
||||
endmodule
|
||||
|
||||
module typed #(
|
||||
parameter type T = logic [6:0]
|
||||
);
|
||||
/*verilator hier_block*/
|
||||
T x;
|
||||
endmodule
|
||||
|
||||
module typed2 #(
|
||||
parameter type TIN = logic,
|
||||
parameter type TOUT = logic
|
||||
);
|
||||
/*verilator hier_block*/
|
||||
TIN i;
|
||||
TOUT o;
|
||||
endmodule
|
||||
|
||||
module nonansi;
|
||||
/*verilator hier_block*/
|
||||
parameter type T = logic;
|
||||
T x;
|
||||
endmodule
|
||||
|
||||
// Sets a type parameter of the block inside it
|
||||
module outer #(
|
||||
parameter type T = logic [4:0]
|
||||
);
|
||||
/*verilator hier_block*/
|
||||
typed #(.T(T)) inner ();
|
||||
endmodule
|
||||
|
||||
module str_blk #(
|
||||
parameter string S = "x"
|
||||
);
|
||||
/*verilator hier_block*/
|
||||
endmodule
|
||||
|
||||
module fixed;
|
||||
/*verilator hier_block*/
|
||||
leaf child ();
|
||||
endmodule
|
||||
|
||||
// Defparam in a module below the block
|
||||
module nested;
|
||||
/*verilator hier_block*/
|
||||
mid m ();
|
||||
endmodule
|
||||
|
||||
module mid;
|
||||
leaf child ();
|
||||
defparam child.N = 3;
|
||||
endmodule
|
||||
|
||||
// Defparam inside a generate construct
|
||||
module generated;
|
||||
/*verilator hier_block*/
|
||||
if (1) begin : g
|
||||
leaf child ();
|
||||
defparam child.N = 4;
|
||||
end
|
||||
endmodule
|
||||
|
||||
module leaf #(
|
||||
parameter int N = 7
|
||||
);
|
||||
endmodule
|
||||
@@ -1,41 +0,0 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain
|
||||
// SPDX-FileCopyrightText: 2024 Antmicro
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t (
|
||||
input clk
|
||||
);
|
||||
logic [31:0] in1;
|
||||
logic [31:0] out1;
|
||||
|
||||
assign in1 = 0;
|
||||
|
||||
Test #(
|
||||
.TYPE_IN(logic [31:0]),
|
||||
.TYPE_OUT(logic [31:0])
|
||||
) test (
|
||||
.out(out1),
|
||||
.in(in1)
|
||||
);
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (out1 !== ~in1) $stop;
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
module Test #(
|
||||
parameter type TYPE_IN = logic [4:0],
|
||||
parameter type TYPE_OUT = logic [7:0]
|
||||
) (
|
||||
output TYPE_IN out,
|
||||
input TYPE_OUT in
|
||||
);
|
||||
/*verilator hier_block*/
|
||||
|
||||
assign out = ~in;
|
||||
endmodule
|
||||
@@ -1,18 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of either the GNU Lesser General Public License Version 3
|
||||
# or the Perl Artistic License Version 2.0.
|
||||
# SPDX-FileCopyrightText: 2024 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile(verilator_flags2=['--hierarchical'])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
@@ -1,52 +0,0 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain
|
||||
// SPDX-FileCopyrightText: 2024 Antmicro
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t (
|
||||
input clk
|
||||
);
|
||||
|
||||
logic [21:0] in1;
|
||||
logic [21:0] out1;
|
||||
|
||||
assign in1 = 0;
|
||||
|
||||
Test #(
|
||||
.TYPE_t(logic [21:0])
|
||||
) test (
|
||||
.out(out1),
|
||||
.in(in1)
|
||||
);
|
||||
|
||||
logic [63:0] in2;
|
||||
logic [63:0] out2;
|
||||
|
||||
assign in2 = 0;
|
||||
Test #(
|
||||
.TYPE_t(logic [63:0])
|
||||
) test2 (
|
||||
.out(out2),
|
||||
.in(in2)
|
||||
);
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (out1 !== ~in1) $stop;
|
||||
if (out2 !== ~in2) $stop;
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
module Test #(
|
||||
parameter type TYPE_t = logic [4:0]
|
||||
) (
|
||||
output TYPE_t out,
|
||||
input TYPE_t in
|
||||
);
|
||||
/*verilator hier_block*/
|
||||
|
||||
assign out = ~in;
|
||||
endmodule
|
||||
@@ -1,18 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of either the GNU Lesser General Public License Version 3
|
||||
# or the Perl Artistic License Version 2.0.
|
||||
# SPDX-FileCopyrightText: 2024 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile(verilator_flags2=['--hierarchical'])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
@@ -1,68 +0,0 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain
|
||||
// SPDX-FileCopyrightText: 2024 Antmicro
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t (
|
||||
input clk
|
||||
);
|
||||
|
||||
logic [2:0] in1;
|
||||
logic [2:0] out1;
|
||||
|
||||
assign in1 = 0;
|
||||
|
||||
Test #(
|
||||
.TYPE_t(logic [2:0])
|
||||
) test (
|
||||
.out(out1),
|
||||
.in(in1)
|
||||
);
|
||||
|
||||
logic [3:0] in2;
|
||||
logic [3:0] out2;
|
||||
|
||||
assign in2 = 0;
|
||||
Test #(
|
||||
.TYPE_t(logic [3:0])
|
||||
) test2 (
|
||||
.out(out2),
|
||||
.in(in2)
|
||||
);
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (out1 !== ~in1) $stop;
|
||||
if (out2 !== ~in2) $stop;
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
module Test #(
|
||||
parameter type TYPE_t = logic [5:0]
|
||||
) (
|
||||
output TYPE_t out,
|
||||
input TYPE_t in
|
||||
);
|
||||
/*verilator hier_block*/
|
||||
|
||||
SubTest #(
|
||||
.TYPE_t(TYPE_t)
|
||||
) subTest (
|
||||
.out(out),
|
||||
.in(in)
|
||||
);
|
||||
endmodule
|
||||
|
||||
module SubTest #(
|
||||
parameter type TYPE_t = logic [8:0]
|
||||
) (
|
||||
output TYPE_t out,
|
||||
input TYPE_t in
|
||||
);
|
||||
/*verilator hier_block*/
|
||||
|
||||
assign out = ~in;
|
||||
endmodule
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of either the GNU Lesser General Public License Version 3
|
||||
# or the Perl Artistic License Version 2.0.
|
||||
# SPDX-FileCopyrightText: 2024 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
test.top_filename = "t/t_typedef_param.v"
|
||||
|
||||
test.compile(verilator_flags2=["--hierarchical"])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user