parent
1bf2ea7643
commit
84f3cc4f48
|
|
@ -33,6 +33,7 @@
|
|||
|
||||
#include "vltstd/vpi_user.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
#include <list>
|
||||
|
|
@ -365,6 +366,7 @@ class VerilatedVpioVar VL_NOT_FINAL : public VerilatedVpioVarBase {
|
|||
} m_mask; // memoized variable mask
|
||||
uint32_t m_entSize = 0; // memoized variable size
|
||||
uint32_t m_bitOffset = 0;
|
||||
int32_t m_partselBits = -1; // Part-select width, -1 means no part-select active
|
||||
|
||||
protected:
|
||||
void* m_varDatap = nullptr; // varp()->datap() adjusted for array entries
|
||||
|
|
@ -384,6 +386,7 @@ public:
|
|||
m_entSize = varp->m_entSize;
|
||||
m_varDatap = varp->m_varDatap;
|
||||
m_index = varp->m_index;
|
||||
m_partselBits = varp->m_partselBits;
|
||||
// Not copying m_prevDatap, must be nullptr
|
||||
} else {
|
||||
m_mask.u32 = 0;
|
||||
|
|
@ -397,10 +400,50 @@ public:
|
|||
return dynamic_cast<VerilatedVpioVar*>(reinterpret_cast<VerilatedVpio*>(h));
|
||||
}
|
||||
uint32_t bitOffset() const override { return m_bitOffset; }
|
||||
uint32_t bitSize() const {
|
||||
if (m_partselBits >= 0) return static_cast<uint32_t>(m_partselBits);
|
||||
return VerilatedVpioVarBase::bitSize();
|
||||
}
|
||||
uint32_t size() const override {
|
||||
if (m_partselBits >= 0) return static_cast<uint32_t>(m_partselBits);
|
||||
return VerilatedVpioVarBase::size();
|
||||
}
|
||||
uint32_t mask() const { return m_mask.u32; }
|
||||
uint8_t mask_byte(int idx) const { return m_mask.u8[idx & 3]; }
|
||||
uint32_t entSize() const { return m_entSize; }
|
||||
const std::vector<int32_t>& index() const { return m_index; }
|
||||
// Create a part-selected view of this variable with the given bit range [hi:lo].
|
||||
VerilatedVpioVar* withPartSelect(int32_t hi, int32_t lo) const {
|
||||
if (isIndexedDimUnpacked()) return nullptr;
|
||||
|
||||
// Need a packed range to select from
|
||||
const VerilatedRange* range = get_range();
|
||||
if (!range) return nullptr;
|
||||
|
||||
// Normalize so sel_lo <= sel_hi
|
||||
const int32_t sel_lo = std::min(hi, lo);
|
||||
const int32_t sel_hi = std::max(hi, lo);
|
||||
const int32_t decl_left = range->left();
|
||||
const int32_t decl_right = range->right();
|
||||
const int32_t decl_lo = std::min(decl_left, decl_right);
|
||||
const int32_t decl_hi = std::max(decl_left, decl_right);
|
||||
|
||||
if (sel_lo < decl_lo || sel_hi > decl_hi) return nullptr;
|
||||
|
||||
const int32_t width = sel_hi - sel_lo + 1;
|
||||
|
||||
// Convert to storage bit position
|
||||
int32_t normalized_lo;
|
||||
if (decl_left > decl_right) // descending [31:0]
|
||||
normalized_lo = sel_lo - decl_lo;
|
||||
else // ascending [0:31]
|
||||
normalized_lo = decl_right - sel_hi;
|
||||
|
||||
auto* ret = new VerilatedVpioVar{this};
|
||||
ret->m_bitOffset += normalized_lo;
|
||||
ret->m_partselBits = width;
|
||||
return ret;
|
||||
}
|
||||
VerilatedVpioVar* withIndex(int32_t index) const {
|
||||
if (VL_UNLIKELY(indexedDim() + 1 >= varp()->dims())) return nullptr;
|
||||
|
||||
|
|
@ -2174,6 +2217,88 @@ void vpi_get_systf_info(vpiHandle /*object*/, p_vpi_systf_data /*systf_data_p*/)
|
|||
VL_VPI_UNIMP_();
|
||||
}
|
||||
|
||||
// Bit range information extracted from a name string by vl_vpi_parse_indices.
|
||||
struct VlVpiBitRange final {
|
||||
int32_t hi = 0;
|
||||
int32_t lo = 0;
|
||||
bool valid = false;
|
||||
};
|
||||
|
||||
// Parse multi-dimensional array indices and an optional trailing bit range from a name string.
|
||||
// e.g., "mem[0][3][2]" -> name becomes "mem", indices = {0, 3, 2}
|
||||
// e.g., "mem[0][3][15:8]" -> name becomes "mem", indices = {0, 3}, bitRange = {15, 8}
|
||||
// e.g., "signal[31:0]" -> name becomes "signal", indices = {}, bitRange = {31, 0}
|
||||
// Returns true if any brackets were parsed successfully, false otherwise.
|
||||
static bool vl_vpi_parse_indices(std::string& name, std::vector<PLI_INT32>& indices,
|
||||
VlVpiBitRange* bitRange = nullptr) {
|
||||
if (name.empty() || name.back() != ']') return false;
|
||||
|
||||
// Collapse consecutive spaces into single spaces
|
||||
name.erase(
|
||||
std::unique(name.begin(), name.end(), [](char a, char b) { return a == ' ' && b == ' '; }),
|
||||
name.end());
|
||||
|
||||
// Only parse brackets after the last escaped identifier's terminating space
|
||||
size_t escapeSpacePos = std::string::npos;
|
||||
const size_t backslashPos = name.rfind('\\');
|
||||
if (backslashPos != std::string::npos) escapeSpacePos = name.find(' ', backslashPos);
|
||||
|
||||
indices.clear();
|
||||
size_t end = name.length();
|
||||
bool first = true;
|
||||
|
||||
while (end > 0 && name[end - 1] == ']') {
|
||||
const size_t close = end - 1;
|
||||
// Search backward for matching '['
|
||||
size_t open = close;
|
||||
while (open > 0 && name[open - 1] != '[') --open;
|
||||
if (open == 0) return false; // No matching '['
|
||||
--open; // Points to '['
|
||||
|
||||
// For escaped identifiers: skip brackets that come before the terminating space
|
||||
if (escapeSpacePos != std::string::npos && open < escapeSpacePos) break;
|
||||
|
||||
const std::string content = name.substr(open + 1, close - open - 1);
|
||||
if (content.empty()) return false; // Empty brackets []
|
||||
|
||||
// On the first (rightmost) bracket, check for bit range [hi:lo]
|
||||
if (first && bitRange) {
|
||||
const size_t colon = content.find(':');
|
||||
if (colon != std::string::npos) {
|
||||
char* endp = nullptr;
|
||||
const long hi_val = std::strtol(content.c_str(), &endp, 10);
|
||||
if (!endp || *endp != ':') return false;
|
||||
const long lo_val = std::strtol(endp + 1, &endp, 10);
|
||||
if (!endp || *endp != '\0') return false;
|
||||
bitRange->hi = static_cast<int32_t>(hi_val);
|
||||
bitRange->lo = static_cast<int32_t>(lo_val);
|
||||
bitRange->valid = true;
|
||||
end = open;
|
||||
first = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
first = false;
|
||||
|
||||
// Parse as integer index
|
||||
char* endp = nullptr;
|
||||
const long val = std::strtol(content.c_str(), &endp, 10);
|
||||
if (!endp || *endp != '\0') return false;
|
||||
indices.push_back(static_cast<PLI_INT32>(val));
|
||||
end = open;
|
||||
}
|
||||
|
||||
if (indices.empty() && !(bitRange && bitRange->valid)) return false;
|
||||
|
||||
// Reverse indices to get them in forward order [0][3][2] -> {0, 3, 2}
|
||||
std::reverse(indices.begin(), indices.end());
|
||||
|
||||
// Truncate name to remove the indices
|
||||
name.erase(end);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// for obtaining handles
|
||||
|
||||
vpiHandle vpi_handle_by_name(PLI_BYTE8* namep, vpiHandle scope) {
|
||||
|
|
@ -2181,22 +2306,29 @@ vpiHandle vpi_handle_by_name(PLI_BYTE8* namep, vpiHandle scope) {
|
|||
VL_VPI_ERROR_RESET_();
|
||||
if (VL_UNLIKELY(!namep)) return nullptr;
|
||||
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_handle_by_name %s %p\n", namep, scope););
|
||||
|
||||
// Parse any array indices and optional bit range from the name
|
||||
// e.g., "mem[0][3][2]" or "signal[15:8]" or "mem[0][3][15:8]"
|
||||
std::string scopeAndName = namep;
|
||||
static thread_local std::vector<PLI_INT32> indices;
|
||||
VlVpiBitRange bitRange;
|
||||
const bool hasIndices = vl_vpi_parse_indices(scopeAndName, indices, &bitRange);
|
||||
|
||||
const VerilatedVar* varp = nullptr;
|
||||
const VerilatedScope* scopep;
|
||||
const VerilatedVpioScope* const voScopep = VerilatedVpioScope::castp(scope);
|
||||
std::string scopeAndName = namep;
|
||||
if (0 == std::strncmp(namep, "$root.", std::strlen("$root."))) {
|
||||
namep += std::strlen("$root.");
|
||||
scopeAndName = namep;
|
||||
|
||||
if (0 == std::strncmp(scopeAndName.c_str(), "$root.", std::strlen("$root."))) {
|
||||
scopeAndName.erase(0, std::strlen("$root."));
|
||||
} else if (voScopep) {
|
||||
const bool scopeIsPackage = VerilatedVpioPackage::castp(scope) != nullptr;
|
||||
scopeAndName = std::string{voScopep->fullname()} + (scopeIsPackage ? "" : ".") + namep;
|
||||
namep = const_cast<PLI_BYTE8*>(scopeAndName.c_str());
|
||||
scopeAndName
|
||||
= std::string{voScopep->fullname()} + (scopeIsPackage ? "" : ".") + scopeAndName;
|
||||
}
|
||||
{
|
||||
// This doesn't yet follow the hierarchy in the proper way
|
||||
bool isPackage = false;
|
||||
scopep = Verilated::threadContextp()->scopeFind(namep);
|
||||
scopep = Verilated::threadContextp()->scopeFind(scopeAndName.c_str());
|
||||
if (scopep) { // Whole thing found as a scope
|
||||
if (scopep->type() == VerilatedScope::SCOPE_MODULE) {
|
||||
return (new VerilatedVpioModule{scopep})->castVpiHandle();
|
||||
|
|
@ -2248,11 +2380,30 @@ vpiHandle vpi_handle_by_name(PLI_BYTE8* namep, vpiHandle scope) {
|
|||
}
|
||||
if (!varp) return nullptr;
|
||||
|
||||
// Create the initial variable handle
|
||||
vpiHandle resultHandle;
|
||||
if (varp->isParam()) {
|
||||
return (new VerilatedVpioParam{varp, scopep})->castVpiHandle();
|
||||
resultHandle = (new VerilatedVpioParam{varp, scopep})->castVpiHandle();
|
||||
} else {
|
||||
return (new VerilatedVpioVar{varp, scopep})->castVpiHandle();
|
||||
resultHandle = (new VerilatedVpioVar{varp, scopep})->castVpiHandle();
|
||||
}
|
||||
|
||||
// If we have indices, apply them using vpi_handle_by_multi_index
|
||||
if (hasIndices && !indices.empty()) {
|
||||
resultHandle = vpi_handle_by_multi_index(resultHandle, indices.size(), indices.data());
|
||||
if (!resultHandle) return nullptr;
|
||||
}
|
||||
|
||||
// If we have a bit range part-select, apply it
|
||||
if (bitRange.valid) {
|
||||
VerilatedVpioVar* const varop = VerilatedVpioVar::castp(resultHandle);
|
||||
if (!varop) return nullptr;
|
||||
VerilatedVpioVar* const partsel = varop->withPartSelect(bitRange.hi, bitRange.lo);
|
||||
if (!partsel) return nullptr;
|
||||
resultHandle = partsel->castVpiHandle();
|
||||
}
|
||||
|
||||
return resultHandle;
|
||||
}
|
||||
|
||||
vpiHandle vpi_handle_by_index(vpiHandle object, PLI_INT32 indx) {
|
||||
|
|
@ -4022,8 +4173,20 @@ PLI_INT32 vpi_control(PLI_INT32 operation, ...) {
|
|||
}
|
||||
}
|
||||
|
||||
vpiHandle vpi_handle_by_multi_index(vpiHandle /*obj*/, PLI_INT32 /*num_index*/,
|
||||
PLI_INT32* /*index_array*/) {
|
||||
VL_VPI_UNIMP_();
|
||||
return nullptr;
|
||||
vpiHandle vpi_handle_by_multi_index(vpiHandle obj, PLI_INT32 num_index, PLI_INT32* index_array) {
|
||||
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_handle_by_multi_index %p %d\n", obj, num_index););
|
||||
VerilatedVpiImp::assertOneCheck();
|
||||
VL_VPI_ERROR_RESET_();
|
||||
|
||||
if (VL_UNLIKELY(!obj)) return nullptr;
|
||||
if (VL_UNLIKELY(!index_array)) return nullptr;
|
||||
if (VL_UNLIKELY(num_index <= 0)) return nullptr;
|
||||
|
||||
vpiHandle result_handle = obj;
|
||||
for (PLI_INT32 i = 0; i < num_index; ++i) {
|
||||
result_handle = vpi_handle_by_index(result_handle, index_array[i]);
|
||||
if (VL_UNLIKELY(!result_handle)) { return nullptr; }
|
||||
}
|
||||
|
||||
return result_handle;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -178,7 +178,6 @@ module t;
|
|||
`checkh(wide_asc, 80'h1234_56789abc_dcb0ffe5);
|
||||
end
|
||||
|
||||
`ifndef VERILATOR // Unsupported
|
||||
begin : memory_1d
|
||||
$display("= uvm_hdl_read/deposit 1D memory");
|
||||
i = uvm_hdl_check_path("t.mem1d[0]");
|
||||
|
|
@ -221,7 +220,6 @@ module t;
|
|||
`checkh(i, 1);
|
||||
`checkh(mem2d[2][3], 32'h2300);
|
||||
end
|
||||
`endif
|
||||
|
||||
begin : t_deposit_bad
|
||||
$display("= uvm_hdl_deposit bad ranges");
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ uvm_dpi_get_tool_name_c() = Verilator
|
|||
= uvm_hdl_deposit multi-bit
|
||||
= uvm_hdl_read/deposit wide decending
|
||||
= uvm_hdl_read/deposit wide ascending
|
||||
= uvm_hdl_read/deposit 1D memory
|
||||
= uvm_hdl_read/deposit 2D memory
|
||||
= uvm_hdl_deposit bad ranges
|
||||
===
|
||||
UVM Report expected on next line:
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ uvm_dpi_get_tool_name_c() = Verilator
|
|||
= uvm_hdl_deposit multi-bit
|
||||
= uvm_hdl_read/deposit wide decending
|
||||
= uvm_hdl_read/deposit wide ascending
|
||||
= uvm_hdl_read/deposit 1D memory
|
||||
= uvm_hdl_read/deposit 2D memory
|
||||
= uvm_hdl_deposit bad ranges
|
||||
===
|
||||
UVM Report expected on next line:
|
||||
|
|
|
|||
|
|
@ -1031,6 +1031,403 @@ int _mon_check_vlog_info() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int _mon_check_multi_index() {
|
||||
s_vpi_value v;
|
||||
v.format = vpiIntVal;
|
||||
|
||||
// vpi_handle_by_multi_index tests
|
||||
|
||||
// Basic tests for vpi_handle_by_multi_index
|
||||
{
|
||||
// 1D unpacked array: quads[2:3] with 62-bit elements
|
||||
TestVpiHandle vh_1d_base = vpi_handle_by_name((PLI_BYTE8*)"t.quads", nullptr);
|
||||
CHECK_RESULT_NZ(vh_1d_base);
|
||||
PLI_INT32 idx_1d[1] = {2};
|
||||
TestVpiHandle vh_1d = vpi_handle_by_multi_index(vh_1d_base, 1, idx_1d);
|
||||
CHECK_RESULT_NZ(vh_1d);
|
||||
CHECK_RESULT(vpi_get(vpiType, vh_1d), vpiReg);
|
||||
CHECK_RESULT(vpi_get(vpiSize, vh_1d), 62);
|
||||
|
||||
// 2D unpacked array: mem_2d[3:0][7:0] with 8-bit elements
|
||||
TestVpiHandle vh_2d_base = vpi_handle_by_name((PLI_BYTE8*)"t.mem_2d", nullptr);
|
||||
CHECK_RESULT_NZ(vh_2d_base);
|
||||
PLI_INT32 idx_2d[2] = {1, 3};
|
||||
TestVpiHandle vh_2d = vpi_handle_by_multi_index(vh_2d_base, 2, idx_2d);
|
||||
CHECK_RESULT_NZ(vh_2d);
|
||||
CHECK_RESULT(vpi_get(vpiType, vh_2d), vpiReg);
|
||||
CHECK_RESULT(vpi_get(vpiSize, vh_2d), 8);
|
||||
vpi_get_value(vh_2d, &v);
|
||||
CHECK_RESULT(v.value.integer, 11); // 1*8 + 3
|
||||
|
||||
// 3D unpacked array: mem_3d[0:1][1:0][0:1] with 96-bit elements
|
||||
TestVpiHandle vh_3d_base = vpi_handle_by_name((PLI_BYTE8*)"t.mem_3d", nullptr);
|
||||
CHECK_RESULT_NZ(vh_3d_base);
|
||||
PLI_INT32 idx_3d[3] = {1, 1, 1};
|
||||
TestVpiHandle vh_3d = vpi_handle_by_multi_index(vh_3d_base, 3, idx_3d);
|
||||
CHECK_RESULT_NZ(vh_3d);
|
||||
CHECK_RESULT(vpi_get(vpiType, vh_3d), vpiReg);
|
||||
CHECK_RESULT(vpi_get(vpiSize, vh_3d), 96);
|
||||
vpi_get_value(vh_3d, &v);
|
||||
CHECK_RESULT(v.value.integer, 7); // (1*4) + (1*2) + 1
|
||||
|
||||
// Verify multi_index matches sequential vpi_handle_by_index
|
||||
TestVpiHandle vh_seq_base = vpi_handle_by_name((PLI_BYTE8*)"t.mem_2d", nullptr);
|
||||
CHECK_RESULT_NZ(vh_seq_base);
|
||||
TestVpiHandle vh_seq_1 = vpi_handle_by_index(vh_seq_base, 1);
|
||||
CHECK_RESULT_NZ(vh_seq_1);
|
||||
TestVpiHandle vh_seq_2 = vpi_handle_by_index(vh_seq_1, 3);
|
||||
CHECK_RESULT_NZ(vh_seq_2);
|
||||
vpi_get_value(vh_seq_2, &v);
|
||||
CHECK_RESULT(v.value.integer, 11);
|
||||
}
|
||||
|
||||
// Error handling for vpi_handle_by_multi_index
|
||||
{
|
||||
// Null handle
|
||||
PLI_INT32 idx_null[1] = {0};
|
||||
TestVpiHandle vh_null_hdl = vpi_handle_by_multi_index(nullptr, 1, idx_null);
|
||||
CHECK_RESULT_Z(vh_null_hdl);
|
||||
|
||||
// Null index array
|
||||
TestVpiHandle vh_base = vpi_handle_by_name((PLI_BYTE8*)"t.quads", nullptr);
|
||||
CHECK_RESULT_NZ(vh_base);
|
||||
TestVpiHandle vh_null_idx = vpi_handle_by_multi_index(vh_base, 1, nullptr);
|
||||
CHECK_RESULT_Z(vh_null_idx);
|
||||
|
||||
// Zero num_index
|
||||
PLI_INT32 idx_zero[1] = {0};
|
||||
TestVpiHandle vh_zero = vpi_handle_by_multi_index(vh_base, 0, idx_zero);
|
||||
CHECK_RESULT_Z(vh_zero);
|
||||
|
||||
// Negative num_index
|
||||
PLI_INT32 idx_neg[1] = {0};
|
||||
TestVpiHandle vh_neg = vpi_handle_by_multi_index(vh_base, -1, idx_neg);
|
||||
CHECK_RESULT_Z(vh_neg);
|
||||
}
|
||||
|
||||
// Bound checking
|
||||
{
|
||||
// Out of bounds on 1D array (quads is [2:3])
|
||||
TestVpiHandle vh_1d = vpi_handle_by_name((PLI_BYTE8*)"t.quads", nullptr);
|
||||
CHECK_RESULT_NZ(vh_1d);
|
||||
PLI_INT32 idx_oob_1d[1] = {99};
|
||||
TestVpiHandle vh_oob_1d = vpi_handle_by_multi_index(vh_1d, 1, idx_oob_1d);
|
||||
CHECK_RESULT_Z(vh_oob_1d);
|
||||
|
||||
// Out of bounds on 2D array (mem_2d[3:0][7:0])
|
||||
TestVpiHandle vh_2d = vpi_handle_by_name((PLI_BYTE8*)"t.mem_2d", nullptr);
|
||||
CHECK_RESULT_NZ(vh_2d);
|
||||
PLI_INT32 idx_oob_2d[2] = {0, 99};
|
||||
TestVpiHandle vh_oob_2d = vpi_handle_by_multi_index(vh_2d, 2, idx_oob_2d);
|
||||
CHECK_RESULT_Z(vh_oob_2d);
|
||||
}
|
||||
|
||||
// Boundary: lowest and highest valid indices on 2D array
|
||||
{
|
||||
TestVpiHandle vh1 = vpi_handle_by_name((PLI_BYTE8*)"t.mem_2d", nullptr);
|
||||
CHECK_RESULT_NZ(vh1);
|
||||
PLI_INT32 lo[2] = {0, 0};
|
||||
TestVpiHandle vh2 = vpi_handle_by_multi_index(vh1, 2, lo);
|
||||
CHECK_RESULT_NZ(vh2);
|
||||
vpi_get_value(vh2, &v);
|
||||
CHECK_RESULT(v.value.integer, 0);
|
||||
PLI_INT32 hi[2] = {3, 7};
|
||||
TestVpiHandle vh3 = vpi_handle_by_multi_index(vh1, 2, hi);
|
||||
CHECK_RESULT_NZ(vh3);
|
||||
vpi_get_value(vh3, &v);
|
||||
CHECK_RESULT(v.value.integer, 31); // 3*8 + 7
|
||||
}
|
||||
|
||||
// Packed dimension indexing: mem_3d fully indexed gives 96-bit element (VLWide)
|
||||
{
|
||||
PLI_INT32 indices[3] = {0, 0, 0};
|
||||
TestVpiHandle vh_elem = vpi_handle_by_name((PLI_BYTE8*)"t.mem_3d", nullptr);
|
||||
CHECK_RESULT_NZ(vh_elem);
|
||||
TestVpiHandle vh_3d = vpi_handle_by_multi_index(vh_elem, 3, indices);
|
||||
CHECK_RESULT_NZ(vh_3d);
|
||||
// Bit selection within element
|
||||
TestVpiHandle vh_3d_bit0 = vpi_handle_by_index(vh_3d, 0);
|
||||
CHECK_RESULT_NZ(vh_3d_bit0);
|
||||
CHECK_RESULT(vpi_get(vpiSize, vh_3d_bit0), 1);
|
||||
// Out of range bit
|
||||
TestVpiHandle vh_3d_oob = vpi_handle_by_index(vh_3d, 96);
|
||||
CHECK_RESULT_Z(vh_3d_oob);
|
||||
}
|
||||
|
||||
// vpi_handle_by_name indexing tests
|
||||
|
||||
{
|
||||
// Escaped identifier with literal brackets in the name
|
||||
TestVpiHandle vh_esc
|
||||
= vpi_handle_by_name((PLI_BYTE8*)"t.\\escaped_with_brackets[3] ", nullptr);
|
||||
CHECK_RESULT_NZ(vh_esc);
|
||||
CHECK_RESULT(vpi_get(vpiType, vh_esc), vpiReg);
|
||||
CHECK_RESULT(vpi_get(vpiSize, vh_esc), 8);
|
||||
vpi_get_value(vh_esc, &v);
|
||||
CHECK_RESULT(v.value.integer, 0x5a);
|
||||
|
||||
// Escaped identifier with whitespace and trailing part-select
|
||||
// 0x5a = 0b01011010, [7:4] = 0b0101 = 5
|
||||
TestVpiHandle vh_esc_ps
|
||||
= vpi_handle_by_name((PLI_BYTE8*)"t.\\escaped_with_brackets[3] [7:4]", nullptr);
|
||||
CHECK_RESULT_NZ(vh_esc_ps);
|
||||
CHECK_RESULT(vpi_get(vpiType, vh_esc_ps), vpiReg);
|
||||
CHECK_RESULT(vpi_get(vpiSize, vh_esc_ps), 4);
|
||||
vpi_get_value(vh_esc_ps, &v);
|
||||
CHECK_RESULT(v.value.integer, 0x5);
|
||||
|
||||
// Escaped identifier with multiple whitespaces and trailing part-select
|
||||
// 0x5a = 0b01011010, [3:0] = 0b1010 = 0xa
|
||||
TestVpiHandle vh_esc_ps_multispace
|
||||
= vpi_handle_by_name((PLI_BYTE8*)"t.\\escaped_with_brackets[3] [3:0]", nullptr);
|
||||
CHECK_RESULT_NZ(vh_esc_ps_multispace);
|
||||
CHECK_RESULT(vpi_get(vpiType, vh_esc_ps_multispace), vpiReg);
|
||||
CHECK_RESULT(vpi_get(vpiSize, vh_esc_ps_multispace), 4);
|
||||
vpi_get_value(vh_esc_ps_multispace, &v);
|
||||
CHECK_RESULT(v.value.integer, 0xa);
|
||||
|
||||
// Escaped instance name (with brackets as part of identifier) accessed through hierarchy
|
||||
TestVpiHandle vh_escaped_inst_sig
|
||||
= vpi_handle_by_name((PLI_BYTE8*)"t.\\escaped.inst[0] .sig", nullptr);
|
||||
CHECK_RESULT_NZ(vh_escaped_inst_sig);
|
||||
CHECK_RESULT(vpi_get(vpiType, vh_escaped_inst_sig), vpiReg);
|
||||
CHECK_RESULT(vpi_get(vpiSize, vh_escaped_inst_sig), 8);
|
||||
|
||||
// Escaped instance name with part-select
|
||||
TestVpiHandle vh_escaped_inst_sig_ps
|
||||
= vpi_handle_by_name((PLI_BYTE8*)"t.\\escaped.inst[0] .sig[3:0]", nullptr);
|
||||
CHECK_RESULT_NZ(vh_escaped_inst_sig_ps);
|
||||
CHECK_RESULT(vpi_get(vpiType, vh_escaped_inst_sig_ps), vpiReg);
|
||||
CHECK_RESULT(vpi_get(vpiSize, vh_escaped_inst_sig_ps), 4);
|
||||
|
||||
// Two escaped identifiers in the path: escaped instance + escaped signal name
|
||||
TestVpiHandle vh_two_escapes
|
||||
= vpi_handle_by_name((PLI_BYTE8*)"t.\\escaped.inst[0] .\\escaped_sig[1] ", nullptr);
|
||||
CHECK_RESULT_NZ(vh_two_escapes);
|
||||
CHECK_RESULT(vpi_get(vpiType, vh_two_escapes), vpiReg);
|
||||
CHECK_RESULT(vpi_get(vpiSize, vh_two_escapes), 8);
|
||||
|
||||
// Two escaped identifiers with part-select and consecutive spaces
|
||||
TestVpiHandle vh_two_escapes_ps = vpi_handle_by_name(
|
||||
(PLI_BYTE8*)"t.\\escaped.inst[0] .\\escaped_sig[1] [3:0]", nullptr);
|
||||
CHECK_RESULT_NZ(vh_two_escapes_ps);
|
||||
CHECK_RESULT(vpi_get(vpiType, vh_two_escapes_ps), vpiReg);
|
||||
CHECK_RESULT(vpi_get(vpiSize, vh_two_escapes_ps), 4);
|
||||
}
|
||||
|
||||
// vpi_handle_by_name with array indexing
|
||||
{
|
||||
TestVpiHandle vh_1d = vpi_handle_by_name((PLI_BYTE8*)"t.quads[2]", nullptr);
|
||||
CHECK_RESULT_NZ(vh_1d);
|
||||
CHECK_RESULT(vpi_get(vpiType, vh_1d), vpiReg);
|
||||
CHECK_RESULT(vpi_get(vpiSize, vh_1d), 62);
|
||||
|
||||
TestVpiHandle vh_2d = vpi_handle_by_name((PLI_BYTE8*)"t.mem_2d[1][3]", nullptr);
|
||||
CHECK_RESULT_NZ(vh_2d);
|
||||
CHECK_RESULT(vpi_get(vpiSize, vh_2d), 8);
|
||||
vpi_get_value(vh_2d, &v);
|
||||
CHECK_RESULT(v.value.integer, 11);
|
||||
|
||||
TestVpiHandle vh_3d = vpi_handle_by_name((PLI_BYTE8*)"t.mem_3d[1][1][1]", nullptr);
|
||||
CHECK_RESULT_NZ(vh_3d);
|
||||
CHECK_RESULT(vpi_get(vpiSize, vh_3d), 96);
|
||||
vpi_get_value(vh_3d, &v);
|
||||
CHECK_RESULT(v.value.integer, 7);
|
||||
}
|
||||
|
||||
// Packed dimension indexing: quads[2] bit selection
|
||||
{
|
||||
TestVpiHandle vh_arr = vpi_handle_by_name((PLI_BYTE8*)"t.quads[2]", nullptr);
|
||||
CHECK_RESULT_NZ(vh_arr);
|
||||
TestVpiHandle vh_bit0 = vpi_handle_by_index(vh_arr, 0);
|
||||
CHECK_RESULT_NZ(vh_bit0);
|
||||
CHECK_RESULT(vpi_get(vpiType, vh_bit0), vpiReg);
|
||||
CHECK_RESULT(vpi_get(vpiSize, vh_bit0), 1);
|
||||
// Try to index into a single bit
|
||||
TestVpiHandle vh_invalid = vpi_handle_by_index(vh_bit0, 0);
|
||||
CHECK_RESULT_Z(vh_invalid);
|
||||
|
||||
TestVpiHandle vh_bit32 = vpi_handle_by_index(vh_arr, 32);
|
||||
CHECK_RESULT_NZ(vh_bit32);
|
||||
CHECK_RESULT(vpi_get(vpiSize, vh_bit32), 1);
|
||||
// Out of range bit should fail
|
||||
TestVpiHandle vh_oob = vpi_handle_by_index(vh_arr, 100);
|
||||
CHECK_RESULT_Z(vh_oob);
|
||||
}
|
||||
|
||||
// Multiple packed dimensions: multi_packed is [3:0][7:0] multi_packed[2:0]
|
||||
{
|
||||
TestVpiHandle vh1 = vpi_handle_by_name((PLI_BYTE8*)"t.multi_packed[1]", nullptr);
|
||||
CHECK_RESULT_NZ(vh1);
|
||||
CHECK_RESULT(vpi_get(vpiSize, vh1), 32); // 4*8
|
||||
// Index into first packed dim -> 8-bit sub-word
|
||||
TestVpiHandle vh2 = vpi_handle_by_index(vh1, 2);
|
||||
CHECK_RESULT_NZ(vh2);
|
||||
CHECK_RESULT(vpi_get(vpiSize, vh2), 8);
|
||||
// Further into bit level
|
||||
TestVpiHandle vh3 = vpi_handle_by_index(vh2, 3);
|
||||
CHECK_RESULT_NZ(vh3);
|
||||
CHECK_RESULT(vpi_get(vpiSize, vh3), 1);
|
||||
}
|
||||
|
||||
// Partial indexing (not all unpacked dimensions)
|
||||
{
|
||||
// mem_2d[1] partially indexes -> remaining [0:7] array
|
||||
TestVpiHandle vh_2d_part = vpi_handle_by_name((PLI_BYTE8*)"t.mem_2d[1]", nullptr);
|
||||
CHECK_RESULT_NZ(vh_2d_part);
|
||||
CHECK_RESULT(vpi_get(vpiType, vh_2d_part), vpiRegArray);
|
||||
CHECK_RESULT(vpi_get(vpiSize, vh_2d_part), 8);
|
||||
TestVpiHandle vh_2d_elem = vpi_handle_by_index(vh_2d_part, 3);
|
||||
CHECK_RESULT_NZ(vh_2d_elem);
|
||||
CHECK_RESULT(vpi_get(vpiType, vh_2d_elem), vpiReg);
|
||||
CHECK_RESULT(vpi_get(vpiSize, vh_2d_elem), 8);
|
||||
|
||||
// mem_3d[0] partially indexes -> remaining [1:0][0:1] = 2*2=4 elements
|
||||
TestVpiHandle vh_3d_part = vpi_handle_by_name((PLI_BYTE8*)"t.mem_3d[0]", nullptr);
|
||||
CHECK_RESULT_NZ(vh_3d_part);
|
||||
CHECK_RESULT(vpi_get(vpiType, vh_3d_part), vpiRegArray);
|
||||
CHECK_RESULT(vpi_get(vpiSize, vh_3d_part), 4);
|
||||
}
|
||||
|
||||
// Invalid syntax in vpi_handle_by_name
|
||||
{
|
||||
// Trailing text after indices
|
||||
CHECK_RESULT_Z(vpi_handle_by_name((PLI_BYTE8*)"t.mem_2d[0][0]bar", nullptr));
|
||||
// Non-integer / non-decimal index values
|
||||
CHECK_RESULT_Z(vpi_handle_by_name((PLI_BYTE8*)"t.mem_2d[0][abc]", nullptr));
|
||||
CHECK_RESULT_Z(vpi_handle_by_name((PLI_BYTE8*)"t.mem_2d[0x2][3]", nullptr));
|
||||
CHECK_RESULT_Z(vpi_handle_by_name((PLI_BYTE8*)"t.mem_2d[-1][0]", nullptr));
|
||||
// Structural bracket errors
|
||||
CHECK_RESULT_Z(vpi_handle_by_name((PLI_BYTE8*)"t.mem_2d[0][]", nullptr));
|
||||
CHECK_RESULT_Z(vpi_handle_by_name((PLI_BYTE8*)"t.mem_2d[0[0]", nullptr));
|
||||
CHECK_RESULT_Z(vpi_handle_by_name((PLI_BYTE8*)"t.mem_2d[0][1", nullptr));
|
||||
CHECK_RESULT_Z(vpi_handle_by_name((PLI_BYTE8*)"t.mem_2d[[0]][1]", nullptr));
|
||||
CHECK_RESULT_Z(vpi_handle_by_name((PLI_BYTE8*)"t.mem_2d[0][1]]", nullptr));
|
||||
CHECK_RESULT_Z(vpi_handle_by_name((PLI_BYTE8*)"t.mem_2d0][1]", nullptr));
|
||||
// Whitespace in indices (unsupported)
|
||||
CHECK_RESULT_Z(vpi_handle_by_name((PLI_BYTE8*)"t.mem_2d[ 0 ][ 1 ]", nullptr));
|
||||
CHECK_RESULT_Z(vpi_handle_by_name((PLI_BYTE8*)"t.mem_2d[0][1] ", nullptr));
|
||||
// Plain identifier with whitespace before part-select (unsupported; only escaped
|
||||
// identifiers may have whitespace before a trailing part-select)
|
||||
CHECK_RESULT_Z(vpi_handle_by_name((PLI_BYTE8*)"t.\\escaped_inst[0] .sig [3:0]", nullptr));
|
||||
// Indexing non-array signals
|
||||
CHECK_RESULT_Z(vpi_handle_by_name((PLI_BYTE8*)"t.onebit[0]", nullptr));
|
||||
CHECK_RESULT_Z(vpi_handle_by_name((PLI_BYTE8*)"t.twoone[0]", nullptr));
|
||||
// Part-select on unpacked-only array
|
||||
CHECK_RESULT_Z(vpi_handle_by_name((PLI_BYTE8*)"t.unpacked_only[3:0]", nullptr));
|
||||
// Range/slice syntax in non-last position or on unpacked dimensions
|
||||
CHECK_RESULT_Z(vpi_handle_by_name((PLI_BYTE8*)"t.mem_2d[0][1:3]", nullptr));
|
||||
CHECK_RESULT_Z(vpi_handle_by_name((PLI_BYTE8*)"t.mem_2d[0:2][0]", nullptr));
|
||||
CHECK_RESULT_Z(vpi_handle_by_name((PLI_BYTE8*)"t.mem_2d[0:2][1:4]", nullptr));
|
||||
CHECK_RESULT_Z(vpi_handle_by_name((PLI_BYTE8*)"t.mem_2d[0+:2][0]", nullptr));
|
||||
CHECK_RESULT_Z(vpi_handle_by_name((PLI_BYTE8*)"t.mem_2d[0-:2][0]", nullptr));
|
||||
CHECK_RESULT_Z(vpi_handle_by_name((PLI_BYTE8*)"t.mem_2d[0:2]", nullptr));
|
||||
CHECK_RESULT_Z(vpi_handle_by_name((PLI_BYTE8*)"t.mem_3d[0:1][0][0]", nullptr));
|
||||
CHECK_RESULT_Z(vpi_handle_by_name((PLI_BYTE8*)"t.mem_3d[0][0:1][0]", nullptr));
|
||||
// Part-select with remaining unpacked dims (not fully indexed)
|
||||
CHECK_RESULT_Z(vpi_handle_by_name((PLI_BYTE8*)"t.mem_3d[0][7:0]", nullptr));
|
||||
CHECK_RESULT_Z(vpi_handle_by_name((PLI_BYTE8*)"t.mem_3d[0][0][7:0]", nullptr));
|
||||
// Part-select out of range: mem_2d[0][0] is 8 bits [7:0]
|
||||
CHECK_RESULT_Z(vpi_handle_by_name((PLI_BYTE8*)"t.mem_2d[0][0][15:8]", nullptr));
|
||||
CHECK_RESULT_Z(vpi_handle_by_name((PLI_BYTE8*)"t.mem_2d[0][0][8:7]", nullptr));
|
||||
}
|
||||
|
||||
// Bit-range part-select via vpi_handle_by_name
|
||||
{
|
||||
// Descending-range element: mem_2d[3][0] = 8'(((3 * 8) + 0)) = 24 = 0x18
|
||||
TestVpiHandle vh_desc_mid = vpi_handle_by_name((PLI_BYTE8*)"t.mem_2d[3][0][7:4]", nullptr);
|
||||
CHECK_RESULT_NZ(vh_desc_mid);
|
||||
CHECK_RESULT(vpi_get(vpiSize, vh_desc_mid), 4);
|
||||
vpi_get_value(vh_desc_mid, &v);
|
||||
CHECK_RESULT(v.value.integer, 0x1); // [7:4] of 0x18
|
||||
|
||||
TestVpiHandle vh_desc_full
|
||||
= vpi_handle_by_name((PLI_BYTE8*)"t.mem_2d[3][0][7:0]", nullptr);
|
||||
CHECK_RESULT_NZ(vh_desc_full);
|
||||
CHECK_RESULT(vpi_get(vpiSize, vh_desc_full), 8);
|
||||
vpi_get_value(vh_desc_full, &v);
|
||||
CHECK_RESULT(v.value.integer, 24); // 0x18
|
||||
|
||||
// Ascending packed range behavior is explicit:
|
||||
// mem_3d has packed declaration [0:95], so [3:0] selects the MSB-end nibble,
|
||||
// while [92:95] selects the LSB-end nibble where value 7 resides.
|
||||
TestVpiHandle vh_asc_lsb
|
||||
= vpi_handle_by_name((PLI_BYTE8*)"t.mem_3d[1][1][1][92:95]", nullptr);
|
||||
CHECK_RESULT_NZ(vh_asc_lsb);
|
||||
CHECK_RESULT(vpi_get(vpiSize, vh_asc_lsb), 4);
|
||||
vpi_get_value(vh_asc_lsb, &v);
|
||||
CHECK_RESULT(v.value.integer, 7); // [92:95] of 0x...000007
|
||||
|
||||
// Select order [95:92] is also accepted and refers to the same bit set as [92:95].
|
||||
TestVpiHandle vh_asc_lsb_rev
|
||||
= vpi_handle_by_name((PLI_BYTE8*)"t.mem_3d[1][1][1][95:92]", nullptr);
|
||||
CHECK_RESULT_NZ(vh_asc_lsb_rev);
|
||||
CHECK_RESULT(vpi_get(vpiSize, vh_asc_lsb_rev), 4);
|
||||
vpi_get_value(vh_asc_lsb_rev, &v);
|
||||
CHECK_RESULT(v.value.integer, 7);
|
||||
|
||||
TestVpiHandle vh_asc_mid
|
||||
= vpi_handle_by_name((PLI_BYTE8*)"t.mem_3d[1][1][1][90:94]", nullptr);
|
||||
CHECK_RESULT_NZ(vh_asc_mid);
|
||||
CHECK_RESULT(vpi_get(vpiSize, vh_asc_mid), 5);
|
||||
vpi_get_value(vh_asc_mid, &v);
|
||||
CHECK_RESULT(v.value.integer, 3); // 5-bit window containing 0b00011
|
||||
|
||||
TestVpiHandle vh_asc_mid_rev
|
||||
= vpi_handle_by_name((PLI_BYTE8*)"t.mem_3d[1][1][1][95:91]", nullptr);
|
||||
CHECK_RESULT_NZ(vh_asc_mid_rev);
|
||||
CHECK_RESULT(vpi_get(vpiSize, vh_asc_mid_rev), 5);
|
||||
vpi_get_value(vh_asc_mid_rev, &v);
|
||||
CHECK_RESULT(v.value.integer, 7);
|
||||
|
||||
// Cross-order select on ascending declaration is allowed and maps by declared indices.
|
||||
TestVpiHandle vh_asc_msb
|
||||
= vpi_handle_by_name((PLI_BYTE8*)"t.mem_3d[1][1][1][3:0]", nullptr);
|
||||
CHECK_RESULT_NZ(vh_asc_msb);
|
||||
CHECK_RESULT(vpi_get(vpiSize, vh_asc_msb), 4);
|
||||
vpi_get_value(vh_asc_msb, &v);
|
||||
CHECK_RESULT(v.value.integer, 0); // [3:0] is MSB-end for [0:95]
|
||||
|
||||
// Part-select combined with array index: mem_2d[2][3] = 19 = 0x13
|
||||
TestVpiHandle vh_2d_arr = vpi_handle_by_name((PLI_BYTE8*)"t.mem_2d[2][3][3:0]", nullptr);
|
||||
CHECK_RESULT_NZ(vh_2d_arr);
|
||||
CHECK_RESULT(vpi_get(vpiSize, vh_2d_arr), 4);
|
||||
vpi_get_value(vh_2d_arr, &v);
|
||||
CHECK_RESULT(v.value.integer, 0x3);
|
||||
|
||||
// Equivalent ascending-order spelling of the MSB-end nibble
|
||||
TestVpiHandle vh_3d_ps = vpi_handle_by_name((PLI_BYTE8*)"t.mem_3d[1][1][1][0:3]", nullptr);
|
||||
CHECK_RESULT_NZ(vh_3d_ps);
|
||||
CHECK_RESULT(vpi_get(vpiSize, vh_3d_ps), 4);
|
||||
vpi_get_value(vh_3d_ps, &v);
|
||||
CHECK_RESULT(v.value.integer, 0);
|
||||
}
|
||||
|
||||
// Part-select write: write 0x2 to mem_2d[3][0][7:4], verify only those bits change
|
||||
{
|
||||
TestVpiHandle vh_ps = vpi_handle_by_name((PLI_BYTE8*)"t.mem_2d[3][0][7:4]", nullptr);
|
||||
CHECK_RESULT_NZ(vh_ps);
|
||||
|
||||
s_vpi_value put_val;
|
||||
put_val.format = vpiIntVal;
|
||||
put_val.value.integer = 0x2;
|
||||
s_vpi_time time_s = {vpiSimTime, 0, 0, 0.0};
|
||||
vpi_put_value(vh_ps, &put_val, &time_s, vpiNoDelay);
|
||||
|
||||
// Read back full element
|
||||
TestVpiHandle vh_full = vpi_handle_by_name((PLI_BYTE8*)"t.mem_2d[3][0]", nullptr);
|
||||
CHECK_RESULT_NZ(vh_full);
|
||||
vpi_get_value(vh_full, &v);
|
||||
CHECK_RESULT(v.value.integer, 0x28); // 0x18 with bits [7:4] changed to 0x2
|
||||
|
||||
// Restore original value
|
||||
put_val.value.integer = 0x1;
|
||||
vpi_put_value(vh_ps, &put_val, &time_s, vpiNoDelay);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" int mon_check() {
|
||||
// Callback from initial block in monitor
|
||||
#ifdef TEST_VERBOSE
|
||||
|
|
@ -1054,6 +1451,7 @@ extern "C" int mon_check() {
|
|||
if (int status = _mon_check_string()) return status;
|
||||
if (int status = _mon_check_putget_str(NULL)) return status;
|
||||
if (int status = _mon_check_vlog_info()) return status;
|
||||
if (int status = _mon_check_multi_index()) return status;
|
||||
if (int status = _mon_check_delayed()) return status;
|
||||
if (int status = _mon_check_too_big()) return status;
|
||||
#ifndef IS_VPI
|
||||
|
|
|
|||
|
|
@ -44,6 +44,14 @@ extern "C" int mon_check();
|
|||
reg [31:0] half_count /*verilator public_flat_rd */ = 0;
|
||||
reg [31:0] delayed /*verilator public_flat_rw */;
|
||||
reg [31:0] delayed_mem [16] /*verilator public_flat_rw */;
|
||||
reg [7:0] \escaped_with_brackets[3] /*verilator public_flat_rw */;
|
||||
reg [7:0] mem_2d[3:0][7:0] /*verilator public_flat_rw */; // Descending indices
|
||||
// verilator lint_off ASCRANGE
|
||||
reg [0:95] mem_3d[0:1][1:0][0:1] /*verilator public_flat_rw */; // Mixed: asc, desc, asc
|
||||
// verilator lint_on ASCRANGE
|
||||
|
||||
reg [3:0] [7:0] multi_packed[2:0] /*verilator public_flat_rw */;
|
||||
reg unpacked_only[7:0];
|
||||
|
||||
reg [7:0] text_byte /*verilator public_flat_rw @(posedge clk) */;
|
||||
reg [15:0] text_half /*verilator public_flat_rw @(posedge clk) */;
|
||||
|
|
@ -91,9 +99,30 @@ extern "C" int mon_check();
|
|||
long1 = 123;
|
||||
real1 = 1.0;
|
||||
str1 = "hello";
|
||||
\escaped_with_brackets[3] = 8'h5a;
|
||||
|
||||
rev = 12'habc;
|
||||
|
||||
for (int i = 0; i < 4; i++) begin
|
||||
for (int j = 0; j < 8; j++) begin
|
||||
mem_2d[i][j] = 8'(((i * 8) + j));
|
||||
end
|
||||
end
|
||||
|
||||
for (int i = 0; i < 2; i++) begin
|
||||
for (int j = 0; j < 2; j++) begin
|
||||
for (int k = 0; k < 2; k++) begin
|
||||
mem_3d[i][j][k] = 96'(((i * 4) + (j * 2) + k));
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for (int i = 0; i < 3; i++) begin
|
||||
for (int j = 0; j < 4; j++) begin
|
||||
multi_packed[i][j] = 8'((i * 4) + j);
|
||||
end
|
||||
end
|
||||
|
||||
`ifdef VERILATOR
|
||||
status = $c32("mon_check()");
|
||||
`endif
|
||||
|
|
@ -147,6 +176,8 @@ extern "C" int mon_check();
|
|||
end
|
||||
endgenerate
|
||||
|
||||
arr #(.LENGTH(8)) \escaped.inst[0] ();
|
||||
|
||||
endmodule : t
|
||||
|
||||
module sub;
|
||||
|
|
@ -164,6 +195,7 @@ module arr;
|
|||
|
||||
reg [LENGTH-1:0] sig /*verilator public_flat_rw*/;
|
||||
reg [LENGTH-1:0] rfr /*verilator public_flat_rw*/;
|
||||
reg [LENGTH-1:0] \escaped_sig[1] /*verilator public_flat_rw*/;
|
||||
|
||||
reg check /*verilator public_flat_rw*/;
|
||||
reg verbose /*verilator public_flat_rw*/;
|
||||
|
|
@ -171,6 +203,7 @@ module arr;
|
|||
initial begin
|
||||
sig = {LENGTH{1'b0}};
|
||||
rfr = {LENGTH{1'b0}};
|
||||
\escaped_sig[1] = {LENGTH{1'b0}};
|
||||
end
|
||||
|
||||
always @(posedge check) begin
|
||||
|
|
|
|||
|
|
@ -59,6 +59,15 @@ extern "C" int mon_check();
|
|||
/*verilator public_flat_rw_on*/
|
||||
reg [31:0] delayed;
|
||||
reg [31:0] delayed_mem [16];
|
||||
reg [7:0] \escaped_with_brackets[3] ;
|
||||
reg [7:0] mem_2d[3:0][7:0]; // Descending indices
|
||||
// verilator lint_off ASCRANGE
|
||||
reg [0:95] mem_3d[0:1][1:0][0:1]; // Mixed: asc, desc, asc
|
||||
// verilator lint_on ASCRANGE
|
||||
|
||||
// Signal with multiple packed dimensions
|
||||
reg [3:0] [7:0] multi_packed[2:0];
|
||||
reg unpacked_only[7:0];
|
||||
/*verilator public_off*/
|
||||
reg invisible2;
|
||||
|
||||
|
|
@ -108,9 +117,30 @@ extern "C" int mon_check();
|
|||
long1 = 123;
|
||||
real1 = 1.0;
|
||||
str1 = "hello";
|
||||
\escaped_with_brackets[3] = 8'h5a;
|
||||
|
||||
rev = 12'habc;
|
||||
|
||||
for (int i = 0; i < 4; i++) begin
|
||||
for (int j = 0; j < 8; j++) begin
|
||||
mem_2d[i][j] = 8'(((i * 8) + j));
|
||||
end
|
||||
end
|
||||
|
||||
for (int i = 0; i < 2; i++) begin
|
||||
for (int j = 0; j < 2; j++) begin
|
||||
for (int k = 0; k < 2; k++) begin
|
||||
mem_3d[i][j][k] = 96'(((i * 4) + (j * 2) + k));
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for (int i = 0; i < 3; i++) begin
|
||||
for (int j = 0; j < 4; j++) begin
|
||||
multi_packed[i][j] = 8'((i * 4) + j);
|
||||
end
|
||||
end
|
||||
|
||||
`ifdef VERILATOR
|
||||
status = $c32("mon_check()");
|
||||
`endif
|
||||
|
|
@ -164,6 +194,8 @@ extern "C" int mon_check();
|
|||
end
|
||||
endgenerate
|
||||
|
||||
arr #(.LENGTH(8)) \escaped.inst[0] ();
|
||||
|
||||
endmodule : t
|
||||
|
||||
module sub;
|
||||
|
|
@ -182,6 +214,7 @@ module arr;
|
|||
/*verilator public_flat_rw_on*/
|
||||
reg [LENGTH-1:0] sig;
|
||||
reg [LENGTH-1:0] rfr;
|
||||
reg [LENGTH-1:0] \escaped_sig[1] /*verilator public_flat_rw*/;
|
||||
|
||||
reg check;
|
||||
reg verbose;
|
||||
|
|
|
|||
|
|
@ -44,6 +44,15 @@ extern "C" int mon_check();
|
|||
reg [31:0] half_count;
|
||||
reg [31:0] delayed;
|
||||
reg [31:0] delayed_mem [16];
|
||||
reg [7:0] \escaped_with_brackets[3] ;
|
||||
reg [7:0] mem_2d[3:0][7:0]; // Descending indices
|
||||
// verilator lint_off ASCRANGE
|
||||
reg [0:95] mem_3d[0:1][1:0][0:1]; // Mixed: asc, desc, asc
|
||||
// verilator lint_on ASCRANGE
|
||||
|
||||
// Signal with multiple packed dimensions
|
||||
reg [3:0] [7:0] multi_packed[2:0];
|
||||
reg unpacked_only[7:0];
|
||||
|
||||
reg [7:0] text_byte;
|
||||
reg [15:0] text_half;
|
||||
|
|
@ -88,9 +97,30 @@ extern "C" int mon_check();
|
|||
long1 = 123;
|
||||
real1 = 1.0;
|
||||
str1 = "hello";
|
||||
\escaped_with_brackets[3] = 8'h5a;
|
||||
|
||||
rev = 12'habc;
|
||||
|
||||
for (int i = 0; i < 4; i++) begin
|
||||
for (int j = 0; j < 8; j++) begin
|
||||
mem_2d[i][j] = 8'(((i * 8) + j));
|
||||
end
|
||||
end
|
||||
|
||||
for (int i = 0; i < 2; i++) begin
|
||||
for (int j = 0; j < 2; j++) begin
|
||||
for (int k = 0; k < 2; k++) begin
|
||||
mem_3d[i][j][k] = 96'(((i * 4) + (j * 2) + k));
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for (int i = 0; i < 3; i++) begin
|
||||
for (int j = 0; j < 4; j++) begin
|
||||
multi_packed[i][j] = 8'((i * 4) + j);
|
||||
end
|
||||
end
|
||||
|
||||
`ifdef VERILATOR
|
||||
status = $c32("mon_check()");
|
||||
`endif
|
||||
|
|
@ -144,6 +174,8 @@ extern "C" int mon_check();
|
|||
end
|
||||
endgenerate
|
||||
|
||||
arr #(.LENGTH(8)) \escaped.inst[0] ();
|
||||
|
||||
endmodule : t
|
||||
|
||||
module sub;
|
||||
|
|
@ -161,6 +193,7 @@ module arr;
|
|||
|
||||
reg [LENGTH-1:0] sig;
|
||||
reg [LENGTH-1:0] rfr;
|
||||
reg [LENGTH-1:0] \escaped_sig[1] /*verilator public_flat_rw*/;
|
||||
|
||||
reg check;
|
||||
reg verbose;
|
||||
|
|
|
|||
Loading…
Reference in New Issue