vpi_get_value_array: add tests and fix some tests.

Some test were not updated to the new vpiReg & vpiRegArray
types.

Signed-off-by: Diego Roux <diegoroux04@protonmail.com>
This commit is contained in:
Diego Roux 2024-11-15 02:02:27 -06:00
parent 164dd8ec96
commit f3abf3c385
No known key found for this signature in database
GPG Key ID: D7D0B7E32653DAD2
6 changed files with 333 additions and 19 deletions

View File

@ -2936,7 +2936,7 @@ void vl_get_value_array(vpiHandle object, p_vpi_arrayvalue arrayvalue_p,
} }
} else { } else {
for (int i = 0; i < num; i++) { for (int i = 0; i < num; i++) {
integers[i] = ptr[index++]; integers[i] = ptr[index];
index = (--index + size) % size; index = (--index + size) % size;
} }
} }
@ -2950,7 +2950,7 @@ void vl_get_value_array(vpiHandle object, p_vpi_arrayvalue arrayvalue_p,
} }
} else { } else {
for (int i = 0; i < num; i++) { for (int i = 0; i < num; i++) {
integers[i] = ptr[index++]; integers[i] = ptr[index];
index = (--index + size) % size; index = (--index + size) % size;
} }
} }
@ -2964,7 +2964,7 @@ void vl_get_value_array(vpiHandle object, p_vpi_arrayvalue arrayvalue_p,
} }
} else { } else {
for (int i = 0; i < num; i++) { for (int i = 0; i < num; i++) {
integers[i] = ptr[index++]; integers[i] = ptr[index];
index = (--index + size) % size; index = (--index + size) % size;
} }
} }
@ -2998,7 +2998,7 @@ void vl_get_value_array(vpiHandle object, p_vpi_arrayvalue arrayvalue_p,
} }
} else { } else {
for (int i = 0; i < num; i++) { for (int i = 0; i < num; i++) {
shortints[i] = ptr[index++]; shortints[i] = ptr[index];
index = (--index + size) % size; index = (--index + size) % size;
} }
} }
@ -3012,7 +3012,7 @@ void vl_get_value_array(vpiHandle object, p_vpi_arrayvalue arrayvalue_p,
} }
} else { } else {
for (int i = 0; i < num; i++) { for (int i = 0; i < num; i++) {
shortints[i] = ptr[index++]; shortints[i] = ptr[index];
index = (--index + size) % size; index = (--index + size) % size;
} }
} }

View File

@ -96,7 +96,7 @@ static int _mon_check_props(TestVpiHandle& handle, int size, int direction, int
} }
// Icarus only supports ranges on memories // Icarus only supports ranges on memories
if (!scalar && !(TestSimulator::is_icarus() && type != vpiMemory)) { if (!scalar && !(TestSimulator::is_icarus() && type != vpiRegArray)) {
TestVpiHandle left_h, right_h; TestVpiHandle left_h, right_h;
// check coherency for vectors // check coherency for vectors
@ -157,11 +157,11 @@ int mon_check_props() {
= {{"onebit", {1, vpiNoDirection, 1, vpiReg}, {0, 0, 0, 0}}, = {{"onebit", {1, vpiNoDirection, 1, vpiReg}, {0, 0, 0, 0}},
{"twoone", {2, vpiNoDirection, 0, vpiReg}, {0, 0, 0, 0}}, {"twoone", {2, vpiNoDirection, 0, vpiReg}, {0, 0, 0, 0}},
{"onetwo", {"onetwo",
{2, vpiNoDirection, 0, TestSimulator::is_verilator() ? vpiReg : vpiMemory}, {2, vpiNoDirection, 0, TestSimulator::is_verilator() ? vpiReg : vpiRegArray},
{0, 0, 0, 0}}, {0, 0, 0, 0}},
{"fourthreetwoone", {"fourthreetwoone",
{2, vpiNoDirection, 0, vpiMemory}, {2, vpiNoDirection, 0, vpiRegArray},
{2, vpiNoDirection, 0, vpiMemoryWord}}, {2, vpiNoDirection, 0, vpiReg}},
{"theint", {32, vpiNoDirection, 0, vpiReg}, {0, 0, 0, 0}}, {"theint", {32, vpiNoDirection, 0, vpiReg}, {0, 0, 0, 0}},
{"clk", {1, vpiInput, 1, vpiPort}, {0, 0, 0, 0}}, {"clk", {1, vpiInput, 1, vpiPort}, {0, 0, 0, 0}},
{"testin", {16, vpiInput, 0, vpiPort}, {0, 0, 0, 0}}, {"testin", {16, vpiInput, 0, vpiPort}, {0, 0, 0, 0}},
@ -184,7 +184,7 @@ int mon_check_props() {
return status; return status;
if (value->children.size) { if (value->children.size) {
int size = 0; int size = 0;
TestVpiHandle iter_h = vpi_iterate(vpiMemoryWord, h); TestVpiHandle iter_h = vpi_iterate(vpiReg, h);
while (TestVpiHandle word_h = vpi_scan(iter_h)) { while (TestVpiHandle word_h = vpi_scan(iter_h)) {
// check size and range // check size and range
if (int status if (int status

View File

@ -0,0 +1,214 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
//
// Copyright 2024 by Diego Roux. 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
//
//*************************************************************************
#ifndef IS_VPI
#include "verilated.h"
#include "verilated_vcd_c.h"
#include "verilated_vpi.h"
#include "Vt_vpi_get_value_array.h"
#include "Vt_vpi_get_value_array__Dpi.h"
#include "svdpi.h"
#endif
#include <cstdio>
#include <cstring>
#include <iostream>
// These require the above. Comment prevents clang-format moving them
#include "TestSimulator.h"
#include "TestVpi.h"
// __FILE__ is too long
#define FILENM "t_vpi_get_value_array.cpp"
#define TEST_MSG \
if (0) printf
//======================================================================
#define CHECK_RESULT_VH(got, exp) \
if ((got) != (exp)) { \
printf("%%Error: %s:%d: GOT = %p EXP = %p\n", FILENM, __LINE__, (got), (exp)); \
return __LINE__; \
}
#define CHECK_RESULT_NZ(got) \
if (!(got)) { \
printf("%%Error: %s:%d: GOT = NULL EXP = !NULL\n", FILENM, __LINE__); \
return __LINE__; \
}
// Use cout to avoid issues with %d/%lx etc
#define CHECK_RESULT(got, exp) \
if ((got) != (exp)) { \
std::cout << std::dec << "%Error: " << FILENM << ":" << __LINE__ << ": GOT = " << (got) \
<< " EXP = " << (exp) << std::endl; \
return __LINE__; \
}
#define CHECK_RESULT_HEX(got, exp) \
if ((got) != (exp)) { \
std::cout << std::dec << "%Error: " << FILENM << ":" << __LINE__ << std::hex \
<< ": GOT = " << (got) << " EXP = " << (exp) << std::endl; \
return __LINE__; \
}
#define CHECK_RESULT_CSTR(got, exp) \
if (std::strcmp((got), (exp))) { \
printf("%%Error: %s:%d: GOT = '%s' EXP = '%s'\n", FILENM, __LINE__, \
(got) ? (got) : "<null>", (exp) ? (exp) : "<null>"); \
return __LINE__; \
}
#define CHECK_RESULT_CSTR_STRIP(got, exp) CHECK_RESULT_CSTR(got + strspn(got, " "), exp)
int mon_check_props(void) {
s_vpi_arrayvalue arrayVal = {0, 0, NULL};
int indexArr[2] = {0};
int num = 4;
{
vpiHandle object = vpi_handle_by_name((PLI_BYTE8*)"TOP.test.read_bytes", NULL);
arrayVal.format = vpiRawTwoStateVal;
vpi_get_value_array(object, &arrayVal, indexArr, num);
PLI_BYTE8* ptr = arrayVal.value.rawvals;
PLI_BYTE8 expected[4] = {0xde, 0xad, 0xbe, 0xef};
for (int i = 0; i < num; i++)
CHECK_RESULT_HEX(ptr[i], expected[i]);
}
{
vpiHandle object = vpi_handle_by_name((PLI_BYTE8*)"TOP.test.read_shorts", NULL);
arrayVal.format = vpiShortIntVal;
vpi_get_value_array(object, &arrayVal, indexArr, num);
PLI_UINT16* ptr = (PLI_UINT16*)arrayVal.value.shortints;
PLI_UINT16 expected[4] = {0xdead, 0xbeef, 0xbeef, 0xdead};
for (int i = 0; i < num; i++)
CHECK_RESULT_HEX(ptr[i], expected[i]);
}
{
vpiHandle object = vpi_handle_by_name((PLI_BYTE8*)"TOP.test.read_integers", NULL);
arrayVal.format = vpiIntVal;
vpi_get_value_array(object, &arrayVal, indexArr, num);
PLI_UINT32* ptr = (PLI_UINT32*)arrayVal.value.integers;
PLI_UINT32 expected[4] = {0x00000000, 0xdeadbeef, 0x00000000, 0xdeadbeef};
for (int i = 0; i < num; i++)
CHECK_RESULT_HEX(ptr[i], expected[i]);
}
{
vpiHandle object = vpi_handle_by_name((PLI_BYTE8*)"TOP.test.read_integers_rl", NULL);
arrayVal.format = vpiIntVal;
vpi_get_value_array(object, &arrayVal, indexArr, num);
PLI_UINT32* ptr = (PLI_UINT32*)arrayVal.value.integers;
PLI_UINT32 expected[4] = {0xdeadbeef, 0x00000000, 0x00000000, 0xdeadbeef};
for (int i = 0; i < num; i++)
CHECK_RESULT_HEX(ptr[i], expected[i]);
}
{
vpiHandle object = vpi_handle_by_name((PLI_BYTE8*)"TOP.test.read_longs", NULL);
arrayVal.format = vpiLongIntVal;
vpi_get_value_array(object, &arrayVal, indexArr, num);
PLI_UINT64* ptr = (PLI_UINT64*)arrayVal.value.longints;
PLI_UINT64 expected[4] = {0x00000000deadbeef, 0x0000000000000000,
0x00000000beefdead, 0x0000000000000000};
for (int i = 0; i < num; i++)
CHECK_RESULT_HEX(ptr[i], expected[i]);
}
{
vpiHandle object = vpi_handle_by_name((PLI_BYTE8*)"TOP.test.read_words", NULL);
arrayVal.format = vpiRawFourStateVal;
vpi_get_value_array(object, &arrayVal, indexArr, num);
PLI_UINT64* ptr = (PLI_UINT64*)arrayVal.value.rawvals;
PLI_UINT64 expected[16] = {0x0000000000000000, 0x0000000000000000, 0x00, 0x00,
0xbeefdead00000000, 0x00000000deadbeef, 0x00, 0x00,
0x0000000000000000, 0x00000000beefdead, 0x00, 0x00,
0xbeefdeaddeadbeef, 0xbeefdeaddeadbeef, 0x00, 0x00};
for (int i = 0; i < num; i++)
CHECK_RESULT_HEX(ptr[i], expected[i]);
}
{
vpiHandle object = vpi_handle_by_name((PLI_BYTE8*)"TOP.test.read_integers", NULL);
arrayVal.format = vpiVector;
vpi_get_value_array(object, &arrayVal, indexArr, num);
p_vpi_vecval ptr = (p_vpi_vecval)arrayVal.value.vectors;
s_vpi_vecval expected[4] = {{0x00000000, 0x000000},
{0xdeadbeef, 0x00000000}, {0x00000000, 0x00000000},
{0xdeadbeef, 0x00000000}};
for (int i = 0; i < num; i++) {
CHECK_RESULT_HEX(ptr[i].aval, expected[i].aval);
CHECK_RESULT_HEX(ptr[i].bval, expected[i].bval);
}
}
return 0;
}
extern "C" int mon_check(void) {
return mon_check_props();
}
#ifndef IS_VPI
int main(int argc, char** argv) {
Verilated::commandArgs(argc, argv);
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
const std::unique_ptr<VM_PREFIX> top{new VM_PREFIX{contextp.get()}};
#ifdef TEST_VERBOSE
contextp->internalsDump();
#endif
while (!contextp->gotFinish()) {
top->eval();
VerilatedVpi::callValueCbs();
}
return 0;
}
#endif

View File

@ -0,0 +1,23 @@
#!/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')
test.compile(make_top_shell=False,
make_main=False,
make_pli=True,
verilator_flags2=["--exe --vpi --no-l2name", test.pli_filename],
iv_flags2=["-g2005-sv -D USE_VPI_NOT_DPI"],
v_flags2=["+define+USE_VPI_NOT_DPI +define+VERILATOR_COMMENTS"])
test.execute(use_libvpi=True)
test.passes()

View File

@ -0,0 +1,77 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// Copyright 2024 by Diego Roux. 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
`ifdef VERILATOR_COMMENTS
`define PUBLIC_FLAT_RD /*verilator public_flat_rd*/
`define PUBLIC_FLAT_RW /*verilator public_flat_rw @(posedge clk)*/
`else
`define PUBLIC_FLAT_RD
`define PUBLIC_FLAT_RW
`endif
module test #(
parameter WIDTH `PUBLIC_FLAT_RD = 32
) (input clk);
`ifdef VERILATOR
`systemc_header
extern "C" int mon_check();
`verilog
`endif
reg [7:0] read_bytes [0:3] `PUBLIC_FLAT_RD;
reg [15:0] read_shorts [0:3] `PUBLIC_FLAT_RD;
reg [31:0] read_integers [0:3] `PUBLIC_FLAT_RD;
reg [31:0] read_integers_rl [3:0] `PUBLIC_FLAT_RD;
reg [63:0] read_longs [0:3] `PUBLIC_FLAT_RD;
reg [127:0] read_words [0:3] `PUBLIC_FLAT_RD;
integer status;
initial begin
read_bytes[0] = 8'hde;
read_bytes[1] = 8'had;
read_bytes[2] = 8'hbe;
read_bytes[3] = 8'hef;
read_shorts[0] = 16'hdead;
read_shorts[1] = 16'hbeef;
read_shorts[2] = 16'hbeef;
read_shorts[3] = 16'hdead;
read_integers[0] = 32'h00000000;
read_integers[1] = 32'hdeadbeef;
read_integers[2] = 32'h00000000;
read_integers[3] = 32'hdeadbeef;
read_integers_rl[0] = 32'hdeadbeef;
read_integers_rl[1] = 32'hdeadbeef;
read_integers_rl[2] = 32'h00000000;
read_integers_rl[3] = 32'h00000000;
read_longs[0] = 64'h00000000deadbeef;
read_longs[1] = 64'h0000000000000000;
read_longs[2] = 64'h00000000beefdead;
read_longs[3] = 64'h0000000000000000;
read_words[0] = 128'h00000000000000000000000000000000;
read_words[1] = 128'hbeefdead0000000000000000deadbeef;
read_words[2] = 128'h000000000000000000000000beefdead;
read_words[3] = 128'hbeefdeaddeadbeefbeefdeaddeadbeef;
status = $c32("mon_check()");
if (status != 0) begin
$write("%%Error: t_vpi_get.cpp:%0d: C Test failed\n", status);
$stop;
end
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -86,8 +86,8 @@ void _mem_check(const char* name, int size, int left, int right, int words) {
TEST_CHECK_NZ(mem_h); TEST_CHECK_NZ(mem_h);
// check type // check type
int vpitype = vpi_get(vpiType, mem_h); int vpitype = vpi_get(vpiType, mem_h);
if (vpitype != vpiMemory && vpitype != vpiReg) { if (vpitype != vpiRegArray && vpitype != vpiReg) {
printf("%%Error: %s:%d vpiType neither vpiMemory or vpiReg: %d\n", FILENM, __LINE__, printf("%%Error: %s:%d vpiType neither vpiRegArray or vpiReg: %d\n", FILENM, __LINE__,
vpitype); vpitype);
errors++; errors++;
} }
@ -99,9 +99,9 @@ void _mem_check(const char* name, int size, int left, int right, int words) {
} }
} }
// iterate and store // iterate and store
if (vpitype == vpiMemory) { if (vpitype == vpiRegArray) {
_mon_check_range(mem_h, words, words, 1); _mon_check_range(mem_h, words, words, 1);
TestVpiHandle iter_h = vpi_iterate(vpiMemoryWord, mem_h); TestVpiHandle iter_h = vpi_iterate(vpiReg, mem_h);
int cnt = 0; int cnt = 0;
while (TestVpiHandle lcl_h = vpi_scan(iter_h)) { while (TestVpiHandle lcl_h = vpi_scan(iter_h)) {
value.format = vpiIntVal; value.format = vpiIntVal;
@ -121,9 +121,9 @@ void _mem_check(const char* name, int size, int left, int right, int words) {
vpi_put_value(mem_h, &value, NULL, vpiNoDelay); vpi_put_value(mem_h, &value, NULL, vpiNoDelay);
TEST_CHECK_Z(vpi_chk_error(&e)); TEST_CHECK_Z(vpi_chk_error(&e));
} }
if (vpitype == vpiMemory) { if (vpitype == vpiRegArray) {
// iterate and accumulate // iterate and accumulate
TestVpiHandle iter_h = vpi_iterate(vpiMemoryWord, mem_h); TestVpiHandle iter_h = vpi_iterate(vpiReg, mem_h);
int cnt = 0; int cnt = 0;
while (TestVpiHandle lcl_h = vpi_scan(iter_h)) { while (TestVpiHandle lcl_h = vpi_scan(iter_h)) {
++cnt; ++cnt;
@ -138,7 +138,7 @@ void _mem_check(const char* name, int size, int left, int right, int words) {
value.format = vpiBinStrVal; value.format = vpiBinStrVal;
vpi_get_value(mem_h, &value); vpi_get_value(mem_h, &value);
TEST_CHECK_Z(vpi_chk_error(&e)); TEST_CHECK_Z(vpi_chk_error(&e));
TEST_CHECK_EQ(std::string{value.value.str}, binStr); TEST_CHECK_EQ(std::string(value.value.str), binStr);
} }
// don't care for non verilator // don't care for non verilator
@ -151,7 +151,7 @@ void _mem_check(const char* name, int size, int left, int right, int words) {
{ {
// make sure trying to get properties that don't exist // make sure trying to get properties that don't exist
// doesn't crash // doesn't crash
TestVpiHandle iter_h = vpi_iterate(vpiMemoryWord, mem_h); TestVpiHandle iter_h = vpi_iterate(vpiReg, mem_h);
int should_be_undefined = vpi_get(vpiSize, iter_h); int should_be_undefined = vpi_get(vpiSize, iter_h);
TEST_CHECK_EQ(should_be_undefined, vpiUndefined); TEST_CHECK_EQ(should_be_undefined, vpiUndefined);
should_be_undefined = vpi_get(vpiIndex, iter_h); should_be_undefined = vpi_get(vpiIndex, iter_h);
@ -163,7 +163,7 @@ void _mem_check(const char* name, int size, int left, int right, int words) {
should_be_NULL = vpi_handle(vpiScope, iter_h); should_be_NULL = vpi_handle(vpiScope, iter_h);
TEST_CHECK_EQ(should_be_NULL, 0); TEST_CHECK_EQ(should_be_NULL, 0);
} }
if (vpitype == vpiMemory) { if (vpitype == vpiRegArray) {
// check vpiRange // check vpiRange
TestVpiHandle iter_h = vpi_iterate(vpiRange, mem_h); TestVpiHandle iter_h = vpi_iterate(vpiRange, mem_h);
TEST_CHECK_NZ(iter_h); TEST_CHECK_NZ(iter_h);