From 0380a36c7644365a15b2c94d8c72dbba3374c7e1 Mon Sep 17 00:00:00 2001 From: Yilou Wang Date: Thu, 9 Jan 2025 14:33:38 +0100 Subject: [PATCH] Fix constrained random for > 64-bit associative arrays (#5670) (#5682) --- include/verilated_random.cpp | 14 +- include/verilated_random.h | 155 +++++++++++++----- include/verilated_types.h | 1 + src/V3Randomize.cpp | 35 ++-- test_regress/t/t_constraint_assoc_arr_bad.out | 9 +- test_regress/t/t_constraint_assoc_arr_bad.v | 10 +- test_regress/t/t_constraint_assoc_arr_basic.v | 34 +++- test_regress/t/t_constraint_assoc_arr_wide.py | 21 +++ test_regress/t/t_constraint_assoc_arr_wide.v | 115 +++++++++++++ 9 files changed, 312 insertions(+), 82 deletions(-) mode change 100644 => 100755 test_regress/t/t_constraint_assoc_arr_bad.v create mode 100755 test_regress/t/t_constraint_assoc_arr_wide.py create mode 100755 test_regress/t/t_constraint_assoc_arr_wide.v diff --git a/include/verilated_random.cpp b/include/verilated_random.cpp index 3dc3b24b0..a525df5c4 100644 --- a/include/verilated_random.cpp +++ b/include/verilated_random.cpp @@ -282,6 +282,7 @@ std::string parseNestedSelect(const std::string& nested_select_expr, indices.push_back(idx); return name; } + //====================================================================== // VlRandomizer:: Methods @@ -467,10 +468,19 @@ bool VlRandomizer::parseSolution(std::iostream& f) { "hex_index contains invalid format"); continue; } - const long long index = std::stoll(hex_index.substr(start + 2), nullptr, 16); - oss << "[" << index << "]"; + std::string trimmed_hex = hex_index.substr(start + 2); + + if (trimmed_hex.size() <= 8) { // Small numbers: <= 32 bits + // Convert to decimal and output directly + oss << "[" << std::to_string(std::stoll(trimmed_hex, nullptr, 16)) << "]"; + } else { // Large numbers: > 32 bits + // Trim leading zeros and handle empty case + trimmed_hex.erase(0, trimmed_hex.find_first_not_of('0')); + oss << "[" << (trimmed_hex.empty() ? "0" : trimmed_hex) << "]"; + } } const std::string indexed_name = oss.str(); + const auto it = std::find_if(m_arr_vars.begin(), m_arr_vars.end(), [&indexed_name](const auto& entry) { return entry.second->m_name == indexed_name; diff --git a/include/verilated_random.h b/include/verilated_random.h index 90d92aa9e..24ba84385 100644 --- a/include/verilated_random.h +++ b/include/verilated_random.h @@ -27,8 +27,10 @@ #include "verilated.h" +#include #include #include +#include //============================================================================= // VlRandomExpr and subclasses represent expressions for the constraint solver. @@ -38,10 +40,10 @@ public: m_name; // Name of the array variable, including index notation (e.g., arr[2][1]) void* const m_datap; // Reference to the array variable data const int m_index; // Flattened (1D) index of the array element - const std::vector m_indices; // Multi-dimensional indices of the array element + const std::vector m_indices; // Multi-dimensional indices of the array element const std::vector m_idxWidths; // Multi-dimensional indices' bit widths - ArrayInfo(const std::string& name, void* datap, int index, const std::vector& indices, + ArrayInfo(const std::string& name, void* datap, int index, const std::vector& indices, const std::vector& idxWidths) : m_name(name) , m_datap(datap) @@ -110,16 +112,31 @@ public: return nullptr; } } - void emitSelect(std::ostream& s, const std::vector& indices, + void emitHexs(std::ostream& s, const std::vector& indices, const size_t bit_width, + size_t idx) const { + for (int j = bit_width - 4; j >= 0; j -= 4) { + s << "0123456789abcdef"[(indices[idx] >> j) & 0xf]; + } + } + void emitSelect(std::ostream& s, const std::vector& indices, const std::vector& idxWidths) const { - for (size_t idx = 0; idx < indices.size(); ++idx) s << "(select "; + const size_t num_indices = idxWidths.size(); + size_t wide_size = 0; + + for (size_t idx = 0; idx < num_indices; ++idx) s << "(select "; s << name(); - for (size_t idx = 0; idx < indices.size(); ++idx) { - s << " #x"; + + for (size_t idx = 0; idx < num_indices; ++idx) { const size_t bit_width = idxWidths[idx]; - for (int j = bit_width - 4; j >= 0; j -= 4) { - s << "0123456789abcdef"[(indices[idx] >> j) & 0xf]; + s << " #x"; + + const size_t emit_count = (bit_width > 32) ? (idxWidths[idx] / 32) : 1; + + for (size_t i = 0; i < emit_count; ++i) { + emitHexs(s, indices, (bit_width > 32) ? 32 : bit_width, wide_size + i); } + + wide_size += (idxWidths[idx] > 32) ? (idxWidths[idx] / 32) : 1; s << ")"; } } @@ -129,7 +146,7 @@ public: const std::string indexed_name = name() + std::to_string(i); const auto it = m_arrVarsRefp->find(indexed_name); if (it != m_arrVarsRefp->end()) { - const std::vector& indices = it->second->m_indices; + const std::vector& indices = it->second->m_indices; const std::vector& idxWidths = it->second->m_idxWidths; emitSelect(s, indices, idxWidths); } else { @@ -165,7 +182,7 @@ public: const std::string indexed_name = name() + std::to_string(j); const auto it = m_arrVarsRefp->find(indexed_name); if (it != m_arrVarsRefp->end()) { - const std::vector& indices = it->second->m_indices; + const std::vector& indices = it->second->m_indices; const std::vector& idxWidths = it->second->m_idxWidths; emitSelect(s, indices, idxWidths); } else { @@ -176,7 +193,6 @@ public: }; //============================================================================= // VlRandomizer is the object holding constraints and variable references. - class VlRandomizer final { // MEMBERS std::vector m_constraints; // Solver-dependent constraints @@ -200,45 +216,89 @@ public: bool next(VlRNG& rngr); template - typename std::enable_if::value>::type - process_key(const T_Key& key, std::string& indexed_name, size_t& integral_index, + typename std::enable_if::value && (sizeof(T_Key) <= 4)>::type + process_key(const T_Key& key, std::string& indexed_name, std::vector& integral_index, const std::string& base_name, size_t& idx_width) { - integral_index = static_cast(key); - indexed_name = base_name + "[" + std::to_string(integral_index) + "]"; + integral_index.push_back(static_cast(key)); + indexed_name + = base_name + "[" + std::to_string(integral_index[integral_index.size() - 1]) + "]"; idx_width = sizeof(T_Key) * 8; } template - typename std::enable_if::value>::type - process_key(const T_Key& key, std::string& indexed_name, size_t& integral_index, + typename std::enable_if::value && (sizeof(T_Key) > 4)>::type + process_key(const T_Key& key, std::string& indexed_name, std::vector& integral_index, const std::string& base_name, size_t& idx_width) { - integral_index = string_to_integral(key); - indexed_name = base_name + "[" + std::to_string(integral_index) + "]"; - idx_width = 64; // 64-bit mask + constexpr size_t segment_bits = 32; + constexpr T_Key mask = (static_cast(1) << segment_bits) - 1; + integral_index.push_back(static_cast(key >> segment_bits)); + integral_index.push_back(static_cast(key & mask)); + + std::ostringstream hex_stream; + hex_stream << std::hex << key; + std::string index_string = hex_stream.str(); + index_string.erase(0, index_string.find_first_not_of('0')); + index_string = index_string.empty() ? "0" : index_string; + + indexed_name = base_name + "[" + index_string + "]"; + + idx_width = sizeof(T_Key) * 8; + } + template + typename std::enable_if::value>::type + process_key(const T_Key& key, std::string& indexed_name, std::vector& integral_index, + const std::string& base_name, size_t& idx_width) { + std::ostringstream hex_stream; + for (size_t i = key.size(); i > 0; --i) { + const size_t segment_value = key.at(i - 1); + hex_stream << std::hex << segment_value; + integral_index.push_back(segment_value); + } + std::string index_string = hex_stream.str(); + index_string.erase(0, index_string.find_first_not_of('0')); + index_string = index_string.empty() ? "0" : index_string; + + indexed_name = base_name + "[" + index_string + "]"; + idx_width = key.size() * 32; + } + template + typename std::enable_if::value>::type + process_key(const T_Key& key, std::string& indexed_name, std::vector& integral_index, + const std::string& base_name, size_t& idx_width) { + // Convert the input string to its ASCII hexadecimal representation + std::ostringstream oss; + for (unsigned char c : key) { + oss << std::hex << std::setw(2) << std::setfill('0') << static_cast(c); + } + std::string hex_str = oss.str(); + // Ensure the hex string is exactly 128 bits (32 hex characters) + hex_str = hex_str.size() > 32 ? hex_str.substr(0, 32) + : std::string(32 - hex_str.size(), '0') + hex_str; + + // Split the hex string into 4 segments (32-bit per segment) + integral_index.clear(); + for (size_t i = 0; i < hex_str.size(); i += 8) { + integral_index.push_back(std::stoul(hex_str.substr(i, 8), nullptr, 16)); + } + + indexed_name = base_name + "[" + + (hex_str.find_first_not_of('0') == std::string::npos + ? "0" + : hex_str.substr(hex_str.find_first_not_of('0'))) + + "]"; + + idx_width = 128; } template typename std::enable_if::value - && !std::is_same::value>::type - process_key(const T_Key& key, std::string& indexed_name, size_t& integral_index, + && !std::is_same::value + && !VlIsVlWide::value>::type + process_key(const T_Key& key, std::string& indexed_name, std::vector& integral_index, const std::string& base_name, size_t& idx_width) { VL_FATAL_MT(__FILE__, __LINE__, "randomize", "Unsupported: Only integral and string index of associative array is " "supported currently."); } - uint64_t string_to_integral(const std::string& str) { - uint64_t result = 0; - for (char c : str) { result = (result << 8) | static_cast(c); } - -#ifdef VL_DEBUG - if (seen_values.count(result) > 0 && seen_values[result] != str) - VL_WARN_MT(__FILE__, __LINE__, "randomize", - "Conflict detected: Different strings mapped to the same 64-bit index."); - seen_values[result] = str; -#endif - - return result; - } - template void write_var(T& var, int width, const char* name, int dimension, std::uint32_t randmodeIdx = std::numeric_limits::max()) { @@ -296,14 +356,14 @@ public: template void record_arr_table(T& var, const std::string name, int dimension, - std::vector indices, std::vector idxWidths) { + std::vector indices, std::vector idxWidths) { const std::string key = generateKey(name, idx); m_arr_vars[key] = std::make_shared(name, &var, idx, indices, idxWidths); ++idx; } template void record_arr_table(VlQueue& var, const std::string name, int dimension, - std::vector indices, std::vector idxWidths) { + std::vector indices, std::vector idxWidths) { if ((dimension > 0) && (var.size() != 0)) { idxWidths.push_back(32); for (size_t i = 0; i < var.size(); ++i) { @@ -316,7 +376,7 @@ public: } template void record_arr_table(VlUnpacked& var, const std::string name, int dimension, - std::vector indices, std::vector idxWidths) { + std::vector indices, std::vector idxWidths) { if ((dimension > 0) && (N_Depth != 0)) { idxWidths.push_back(32); for (size_t i = 0; i < N_Depth; ++i) { @@ -330,20 +390,27 @@ public: } template void record_arr_table(VlAssocArray& var, const std::string name, int dimension, - std::vector indices, std::vector idxWidths) { + std::vector indices, std::vector idxWidths) { if ((dimension > 0) && (var.size() != 0)) { for (auto it = var.begin(); it != var.end(); ++it) { const T_Key& key = it->first; const T_Value& value = it->second; + std::string indexed_name; - size_t integral_index; - size_t idx_width; + std::vector integral_index; + size_t idx_width = 0; + process_key(key, indexed_name, integral_index, name, idx_width); + + // Update indices and widths idxWidths.push_back(idx_width); - indices.push_back(integral_index); + indices.insert(indices.end(), integral_index.begin(), integral_index.end()); + record_arr_table(var.at(key), indexed_name, dimension - 1, indices, idxWidths); + + // Cleanup indices and widths idxWidths.pop_back(); - indices.pop_back(); + indices.resize(indices.size() - integral_index.size()); } } } diff --git a/include/verilated_types.h b/include/verilated_types.h index 84caafa27..851366b95 100644 --- a/include/verilated_types.h +++ b/include/verilated_types.h @@ -451,6 +451,7 @@ struct VlWide final { // METHODS const EData& at(size_t index) const { return m_storage[index]; } EData& at(size_t index) { return m_storage[index]; } + size_t size() const { return N_Words; } WData* data() { return &m_storage[0]; } const WData* data() const { return &m_storage[0]; } bool operator<(const VlWide& rhs) const { diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp index 96c3f6945..0fdb58a16 100644 --- a/src/V3Randomize.cpp +++ b/src/V3Randomize.cpp @@ -710,15 +710,19 @@ class ConstraintExprVisitor final : public VNVisitor { if (editFormat(nodep)) return; FileLine* const fl = nodep->fileline(); if (VN_IS(nodep->bitp(), CvtPackString)) { - // Extract and truncate the string index to fit within 64 bits AstCvtPackString* const stringp = VN_AS(nodep->bitp(), CvtPackString); + const size_t stringSize = VN_AS(stringp->lhsp(), Const)->width(); + if (stringSize > 128) { + stringp->v3warn( + CONSTRAINTIGN, + "Unsupported: Constrained randomization of associative array keys of " + << stringSize << "bits, limit is 128 bits"); + } VNRelinker handle; - AstNodeExpr* const strIdxp = new AstSFormatF{ - fl, "#x%16x", false, - new AstAnd{fl, stringp->lhsp()->unlinkFrBack(&handle), - new AstConst(fl, AstConst::Unsized64{}, 0xFFFFFFFFFFFFFFFF)}}; - handle.relink(strIdxp); - editSMT(nodep, nodep->fromp(), strIdxp); + AstNodeExpr* const idxp + = new AstSFormatF{fl, "#x%32x", false, stringp->lhsp()->unlinkFrBack(&handle)}; + handle.relink(idxp); + editSMT(nodep, nodep->fromp(), idxp); } else { VNRelinker handle; const int actual_width = nodep->bitp()->width(); @@ -728,16 +732,10 @@ class ConstraintExprVisitor final : public VNVisitor { fmt = "#x%2x"; } else if (actual_width <= 16) { fmt = "#x%4x"; - } else if (actual_width <= 32) { - fmt = "#x%8x"; - } else if (actual_width <= 64) { - fmt = "#x%16x"; } else { - nodep->v3warn(CONSTRAINTIGN, - "Unsupported: Associative array index " - "widths of more than 64 bits during constraint randomization."); - return; + fmt = "#x%" + std::to_string(VL_WORDS_I(actual_width) * 8) + "x"; } + AstNodeExpr* const idxp = new AstSFormatF{fl, fmt, false, nodep->bitp()->unlinkFrBack(&handle)}; handle.relink(idxp); @@ -1450,11 +1448,8 @@ class RandomizeVisitor final : public VNVisitor { AstNodeStmt* stmtsp = nullptr; auto createLoopIndex = [&](AstNodeDType* tempDTypep) { if (VN_IS(tempDTypep, AssocArrayDType)) { - return new AstVar{ - fl, VVarType::VAR, uniqueNamep->get(""), - dtypep->findBasicDType( - ((AstBasicDType*)VN_AS(tempDTypep, AssocArrayDType)->keyDTypep()) - ->keyword())}; + return new AstVar{fl, VVarType::VAR, uniqueNamep->get(""), + VN_AS(tempDTypep, AssocArrayDType)->keyDTypep()}; } return new AstVar{fl, VVarType::VAR, uniqueNamep->get(""), dtypep->findBasicDType(VBasicDTypeKwd::UINT32)}; diff --git a/test_regress/t/t_constraint_assoc_arr_bad.out b/test_regress/t/t_constraint_assoc_arr_bad.out index a048591fc..0e919e3b9 100644 --- a/test_regress/t/t_constraint_assoc_arr_bad.out +++ b/test_regress/t/t_constraint_assoc_arr_bad.out @@ -1,9 +1,6 @@ -%Warning-CONSTRAINTIGN: t/t_constraint_assoc_arr_bad.v:14:22: Unsupported: Associative array index widths of more than 64 bits during constraint randomization. - 14 | bit_index_arr[79'd66] == 65; - | ^ +%Warning-CONSTRAINTIGN: t/t_constraint_assoc_arr_bad.v:12:20: Unsupported: Constrained randomization of associative array keys of 144bits, limit is 128 bits + 12 | string_arr["a_very_long_string"] == 65; + | ^~~~~~~~~~~~~~~~~~~~ ... For warning description see https://verilator.org/warn/CONSTRAINTIGN?v=latest ... Use "/* verilator lint_off CONSTRAINTIGN */" and lint_on around source to disable this message. -%Warning-CONSTRAINTIGN: t/t_constraint_assoc_arr_bad.v:15:24: Unsupported: Associative array index widths of more than 64 bits during constraint randomization. - 15 | logic_index_arr[65'd3] == 70; - | ^ %Error: Exiting due to diff --git a/test_regress/t/t_constraint_assoc_arr_bad.v b/test_regress/t/t_constraint_assoc_arr_bad.v old mode 100644 new mode 100755 index 2050f2643..7ffeba96a --- a/test_regress/t/t_constraint_assoc_arr_bad.v +++ b/test_regress/t/t_constraint_assoc_arr_bad.v @@ -4,19 +4,15 @@ // any use, without warranty, 2024 by PlanV GmbH. // SPDX-License-Identifier: CC0-1.0 - class AssocArrayWarningTest; - rand int bit_index_arr [bit[78:0]]; - rand int logic_index_arr [logic[64:0]]; + rand int string_arr [string]; constraint c { - bit_index_arr[79'd66] == 65; - logic_index_arr[65'd3] == 70; + string_arr["a_very_long_string"] == 65; } function new(); - bit_index_arr = '{79'd66:0}; - logic_index_arr = '{65'd3:0}; + string_arr["a_very_long_string"] = 0; endfunction endclass diff --git a/test_regress/t/t_constraint_assoc_arr_basic.v b/test_regress/t/t_constraint_assoc_arr_basic.v index 105cdb96a..1cd43562d 100644 --- a/test_regress/t/t_constraint_assoc_arr_basic.v +++ b/test_regress/t/t_constraint_assoc_arr_basic.v @@ -147,11 +147,33 @@ class constrained_2d_associative_array; /* verilator lint_off SIDEEFFECT */ endclass +class AssocArray64bitMoreTest; + + rand int bit_index_arr [bit[78:0]]; + rand int logic_index_arr [logic[64:0]]; + + constraint c { + bit_index_arr[79'd66] == 65; + logic_index_arr[65'd3] == 70; + } + function new(); + bit_index_arr = '{79'd66:0}; + logic_index_arr = '{65'd3:0}; + endfunction + function void self_check(); + if (bit_index_arr[79'd66] != 65) $stop; + if (logic_index_arr[65'd3] != 70) $stop; + endfunction + +endclass + module t_constraint_assoc_arr_basic; constrained_associative_array_basic my_array; constrained_1d_associative_array my_1d_array; constrained_2d_associative_array my_2d_array; + + AssocArray64bitMoreTest test_obj; int success; initial begin @@ -165,10 +187,16 @@ module t_constraint_assoc_arr_basic; if (success == 0) $stop; my_1d_array.self_check(); - my_1d_array = new(); - success = my_1d_array.randomize(); + my_2d_array = new(); + success = my_2d_array.randomize(); if (success == 0) $stop; - my_1d_array.self_check(); + my_2d_array.self_check(); + + test_obj = new(); + repeat(2) begin + success = test_obj.randomize(); + if (success != 1) $stop; + end // my_1d_array.debug_display(); // my_2d_array.debug_display(); diff --git a/test_regress/t/t_constraint_assoc_arr_wide.py b/test_regress/t/t_constraint_assoc_arr_wide.py new file mode 100755 index 000000000..a2b131082 --- /dev/null +++ b/test_regress/t/t_constraint_assoc_arr_wide.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2024 by Wilson Snyder. 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-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('simulator') + +if not test.have_solver: + test.skip("No constraint solver installed") + +test.compile() + +test.execute() + +test.passes() diff --git a/test_regress/t/t_constraint_assoc_arr_wide.v b/test_regress/t/t_constraint_assoc_arr_wide.v new file mode 100755 index 000000000..52dca3fc2 --- /dev/null +++ b/test_regress/t/t_constraint_assoc_arr_wide.v @@ -0,0 +1,115 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2025 by PlanV GmbH. +// SPDX-License-Identifier: CC0-1.0 + +class AssocIntegralWide; + + rand bit [31:0] assoc_array[bit[64:0]]; + rand bit [31:0] assoc_array_128[bit[128:0]]; + rand bit [31:0] assoc_array_2d[bit[64:0]][bit[128:0]]; + + constraint valid_entries { + assoc_array[65'd6] == 32'd8; + assoc_array[65'h1FFFFFFFFFFFFFFFF] == 32'hDEADBEEF; + + assoc_array_128[129'd6] == 32'd16; + assoc_array_128[129'h1FFFFFFFFFFFFFFFFFFFFFFFF] == 32'hCAFEBABE; + + assoc_array_2d[65'd6][129'd6] == 32'd32; + assoc_array_2d[65'h1FFFFFFFFFFFFFFFF][129'h1FFFFFFFFFFFFFFFFFFFFFFFF] == 32'hBADF00D; + } + + // Constructor to initialize arrays + function new(); + assoc_array[65'd0] = 32'd0; + assoc_array[65'd6] = 32'd0; + assoc_array[65'h1FFFFFFFFFFFFFFFF] = 32'd0; + + assoc_array_128[129'd0] = 32'd0; + assoc_array_128[129'd6] = 32'd0; + assoc_array_128[129'h1FFFFFFFFFFFFFFFFFFFFFFFF] = 32'd0; + + assoc_array_2d[65'd6][129'd6] = 32'd0; + assoc_array_2d[65'h1FFFFFFFFFFFFFFFF][129'h1FFFFFFFFFFFFFFFFFFFFFFFF] = 32'd0; + endfunction + + // Self-check function to verify constraints + function void self_check(); + if (assoc_array[65'd6] != 32'd8) + $stop; + if (assoc_array[65'h1FFFFFFFFFFFFFFFF] != 32'hDEADBEEF) + $stop; + + if (assoc_array_128[129'd6] != 32'd16) + $stop; + if (assoc_array_128[129'h1FFFFFFFFFFFFFFFFFFFFFFFF] != 32'hCAFEBABE) + $stop; + + if (assoc_array_2d[65'd6][129'd6] != 32'd32) + $stop; + if (assoc_array_2d[65'h1FFFFFFFFFFFFFFFF][129'h1FFFFFFFFFFFFFFFFFFFFFFFF] != 32'hBADF00D) + $stop; + endfunction + +endclass + +class AssocStringWide; + + rand bit [31:0] array_32[string]; + rand bit [31:0] array_64[string]; + rand bit [31:0] array_96[string]; + rand bit [31:0] array_128[string]; + + constraint valid_entries { + // <= 32 bits + array_32["pv"] == 32'd10; + // > 32 and <= 64 bits + array_64["verilog"] == 32'd20; + // > 32 and <= 64 bits + array_96["verilator"] == 32'd30; + // > 64 and <= 96 bits + array_128["systemverilog"] == 32'd40; + } + + function new(); + array_32["pv"] = 32'd0; + array_64["verilog"] = 32'd0; + array_96["verilator"] = 32'd0; + array_128["systemverilog"] = 32'd0; + endfunction + + function void self_check(); + if (array_32["pv"] != 32'd10) $stop; + if (array_64["verilog"] != 32'd20) $stop; + if (array_96["verilator"] != 32'd30) $stop; + if (array_128["systemverilog"] != 32'd40) $stop; + endfunction + +endclass + + +module t_constraint_assoc_arr_wide; + + AssocIntegralWide integral_wide; + AssocStringWide string_wide; + + int success; + initial begin + + integral_wide = new(); + string_wide = new(); + + success = integral_wide.randomize(); + if (success != 1) $stop; + integral_wide.self_check(); + + success = string_wide.randomize(); + if (success != 1) $stop; + string_wide.self_check(); + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule