diff --git a/include/verilated_vpi.cpp b/include/verilated_vpi.cpp index 7d623a0d4..239088f26 100644 --- a/include/verilated_vpi.cpp +++ b/include/verilated_vpi.cpp @@ -2936,7 +2936,7 @@ void vl_get_value_array(vpiHandle object, p_vpi_arrayvalue arrayvalue_p, } } else { for (int i = 0; i < num; i++) { - integers[i] = ptr[index++]; + integers[i] = ptr[index]; index = (--index + size) % size; } } @@ -2950,7 +2950,7 @@ void vl_get_value_array(vpiHandle object, p_vpi_arrayvalue arrayvalue_p, } } else { for (int i = 0; i < num; i++) { - integers[i] = ptr[index++]; + integers[i] = ptr[index]; index = (--index + size) % size; } } @@ -2964,7 +2964,7 @@ void vl_get_value_array(vpiHandle object, p_vpi_arrayvalue arrayvalue_p, } } else { for (int i = 0; i < num; i++) { - integers[i] = ptr[index++]; + integers[i] = ptr[index]; index = (--index + size) % size; } } @@ -2998,7 +2998,7 @@ void vl_get_value_array(vpiHandle object, p_vpi_arrayvalue arrayvalue_p, } } else { for (int i = 0; i < num; i++) { - shortints[i] = ptr[index++]; + shortints[i] = ptr[index]; index = (--index + size) % size; } } @@ -3012,7 +3012,7 @@ void vl_get_value_array(vpiHandle object, p_vpi_arrayvalue arrayvalue_p, } } else { for (int i = 0; i < num; i++) { - shortints[i] = ptr[index++]; + shortints[i] = ptr[index]; index = (--index + size) % size; } } diff --git a/test_regress/t/t_vpi_get.cpp b/test_regress/t/t_vpi_get.cpp index 1d63845b4..18e721336 100644 --- a/test_regress/t/t_vpi_get.cpp +++ b/test_regress/t/t_vpi_get.cpp @@ -96,7 +96,7 @@ static int _mon_check_props(TestVpiHandle& handle, int size, int direction, int } // 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; // check coherency for vectors @@ -157,11 +157,11 @@ int mon_check_props() { = {{"onebit", {1, vpiNoDirection, 1, vpiReg}, {0, 0, 0, 0}}, {"twoone", {2, vpiNoDirection, 0, vpiReg}, {0, 0, 0, 0}}, {"onetwo", - {2, vpiNoDirection, 0, TestSimulator::is_verilator() ? vpiReg : vpiMemory}, + {2, vpiNoDirection, 0, TestSimulator::is_verilator() ? vpiReg : vpiRegArray}, {0, 0, 0, 0}}, {"fourthreetwoone", - {2, vpiNoDirection, 0, vpiMemory}, - {2, vpiNoDirection, 0, vpiMemoryWord}}, + {2, vpiNoDirection, 0, vpiRegArray}, + {2, vpiNoDirection, 0, vpiReg}}, {"theint", {32, vpiNoDirection, 0, vpiReg}, {0, 0, 0, 0}}, {"clk", {1, vpiInput, 1, vpiPort}, {0, 0, 0, 0}}, {"testin", {16, vpiInput, 0, vpiPort}, {0, 0, 0, 0}}, @@ -184,7 +184,7 @@ int mon_check_props() { return status; if (value->children.size) { 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)) { // check size and range if (int status diff --git a/test_regress/t/t_vpi_get_value_array.cpp b/test_regress/t/t_vpi_get_value_array.cpp new file mode 100644 index 000000000..82da63d65 --- /dev/null +++ b/test_regress/t/t_vpi_get_value_array.cpp @@ -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 +#include +#include + +// 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) : "", (exp) ? (exp) : ""); \ + 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 contextp{new VerilatedContext}; + const std::unique_ptr top{new VM_PREFIX{contextp.get()}}; + +#ifdef TEST_VERBOSE + contextp->internalsDump(); +#endif + + while (!contextp->gotFinish()) { + top->eval(); + VerilatedVpi::callValueCbs(); + } + + return 0; +} + +#endif \ No newline at end of file diff --git a/test_regress/t/t_vpi_get_value_array.py b/test_regress/t/t_vpi_get_value_array.py new file mode 100644 index 000000000..9f7ed1832 --- /dev/null +++ b/test_regress/t/t_vpi_get_value_array.py @@ -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() diff --git a/test_regress/t/t_vpi_get_value_array.v b/test_regress/t/t_vpi_get_value_array.v new file mode 100644 index 000000000..1d51cb75d --- /dev/null +++ b/test_regress/t/t_vpi_get_value_array.v @@ -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 diff --git a/test_regress/t/t_vpi_memory.cpp b/test_regress/t/t_vpi_memory.cpp index 9ef3fbe97..7bf87704f 100644 --- a/test_regress/t/t_vpi_memory.cpp +++ b/test_regress/t/t_vpi_memory.cpp @@ -86,8 +86,8 @@ void _mem_check(const char* name, int size, int left, int right, int words) { TEST_CHECK_NZ(mem_h); // check type int vpitype = vpi_get(vpiType, mem_h); - if (vpitype != vpiMemory && vpitype != vpiReg) { - printf("%%Error: %s:%d vpiType neither vpiMemory or vpiReg: %d\n", FILENM, __LINE__, + if (vpitype != vpiRegArray && vpitype != vpiReg) { + printf("%%Error: %s:%d vpiType neither vpiRegArray or vpiReg: %d\n", FILENM, __LINE__, vpitype); errors++; } @@ -99,9 +99,9 @@ void _mem_check(const char* name, int size, int left, int right, int words) { } } // iterate and store - if (vpitype == vpiMemory) { + if (vpitype == vpiRegArray) { _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; while (TestVpiHandle lcl_h = vpi_scan(iter_h)) { 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); TEST_CHECK_Z(vpi_chk_error(&e)); } - if (vpitype == vpiMemory) { + if (vpitype == vpiRegArray) { // iterate and accumulate - TestVpiHandle iter_h = vpi_iterate(vpiMemoryWord, mem_h); + TestVpiHandle iter_h = vpi_iterate(vpiReg, mem_h); int cnt = 0; while (TestVpiHandle lcl_h = vpi_scan(iter_h)) { ++cnt; @@ -138,7 +138,7 @@ void _mem_check(const char* name, int size, int left, int right, int words) { value.format = vpiBinStrVal; vpi_get_value(mem_h, &value); 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 @@ -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 // 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); TEST_CHECK_EQ(should_be_undefined, vpiUndefined); 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); TEST_CHECK_EQ(should_be_NULL, 0); } - if (vpitype == vpiMemory) { + if (vpitype == vpiRegArray) { // check vpiRange TestVpiHandle iter_h = vpi_iterate(vpiRange, mem_h); TEST_CHECK_NZ(iter_h);