forked from github/verilator
Tests: Add t_dpi_accessors
This commit is contained in:
parent
996f48fcf0
commit
aa3a417e97
1
.gitignore
vendored
1
.gitignore
vendored
@ -16,6 +16,7 @@ config.cache
|
||||
config.status
|
||||
configure
|
||||
dddrun*
|
||||
doxygen-doc
|
||||
gdbrun*
|
||||
internals.txt
|
||||
verilator.pdf
|
||||
|
730
test_regress/t/t_dpi_accessors.cpp
Normal file
730
test_regress/t/t_dpi_accessors.cpp
Normal file
@ -0,0 +1,730 @@
|
||||
// -*- C++ -*-
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2012 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.
|
||||
//
|
||||
// Verilator is distributed in the hope that it will be useful, but WITHOUT
|
||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
// more details.
|
||||
//
|
||||
// Contributed by Jeremy Bennett and Jie Xu
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
#include "svdpi.h"
|
||||
|
||||
#include "Vt_dpi_accessors.h"
|
||||
#include "Vt_dpi_accessors__Dpi.h"
|
||||
|
||||
|
||||
using std::cout;
|
||||
using std::dec;
|
||||
using std::endl;
|
||||
using std::hex;
|
||||
using std::setfill;
|
||||
using std::setw;
|
||||
|
||||
|
||||
// Convenience function to check we didn't finish unexpectedly
|
||||
static void
|
||||
checkFinish (const char *msg)
|
||||
{
|
||||
if (Verilated::gotFinish ()) {
|
||||
vl_fatal (__FILE__, __LINE__, "dut", msg);
|
||||
exit (1);
|
||||
}
|
||||
} // checkFinish ()
|
||||
|
||||
|
||||
// Convenience function to log the value of a register in hex. Only in verbose
|
||||
// mode.
|
||||
static void
|
||||
logReg (int clk,
|
||||
const char *desc,
|
||||
int val,
|
||||
const char *note)
|
||||
{
|
||||
#ifdef TEST_VERBOSE
|
||||
cout << "clk = " << clk << ", " << desc << " = " << val << note << endl;
|
||||
#endif
|
||||
} // logReg ()
|
||||
|
||||
|
||||
// Convenience function to log the value of a register in hex. Only in verbose
|
||||
// mode.
|
||||
static void
|
||||
logRegHex (int clk,
|
||||
const char *desc,
|
||||
int bitWidth,
|
||||
int val,
|
||||
const char *note)
|
||||
{
|
||||
#ifdef TEST_VERBOSE
|
||||
cout << "clk = " << clk << ", " << desc << " = " << bitWidth << "\'h" << hex
|
||||
<< setw ((bitWidth - 1) / 4 + 1) << setfill ('0') << val
|
||||
<< setfill (' ') << setw (0) << dec << note << endl;
|
||||
#endif
|
||||
|
||||
} // logRegHex ()
|
||||
|
||||
|
||||
// Convenience function to check we got an expected result. Silent on success.
|
||||
static void
|
||||
checkResult (bool p,
|
||||
const char *msg_fail)
|
||||
{
|
||||
if (!p) {
|
||||
vl_fatal (__FILE__, __LINE__, "dut", msg_fail);
|
||||
}
|
||||
} // checkResult ()
|
||||
|
||||
|
||||
// Main function instantiates the model and steps through the test.
|
||||
int main ()
|
||||
{
|
||||
Vt_dpi_accessors *dut = new Vt_dpi_accessors ("dut");
|
||||
svSetScope (svGetScopeFromName ("dut.v"));
|
||||
|
||||
// evaluate the model with no signal changes to get the initial blocks
|
||||
// executed.
|
||||
dut->eval ();
|
||||
|
||||
#ifdef TEST_VERBOSE
|
||||
cout << "Initial DPI values" << endl;
|
||||
cout << "==================" << endl;
|
||||
#endif
|
||||
|
||||
int a = (int) a_read ();
|
||||
int b = (int) b_read ();
|
||||
int mem32 = (int) mem32_read ();
|
||||
int c = (int) c_read ();
|
||||
int d = (int) d_read ();
|
||||
int e = (int) e_read ();
|
||||
int f = (int) f_read ();
|
||||
|
||||
#ifdef TEST_VERBOSE
|
||||
cout << "Read a = " << a << endl;
|
||||
cout << "Read b = 8'h" << hex << setw (2) << setfill ('0') << b
|
||||
<< setfill (' ') << setw (0) << dec << endl;
|
||||
cout << "Read mem32 = 8'h" << hex << setw (2) << setfill ('0') << mem32
|
||||
<< setfill (' ') << setw (0) << dec << endl;
|
||||
cout << "Read c = " << c << endl;
|
||||
cout << "Read d = 8'h" << hex << setw (2) << setfill ('0') << d
|
||||
<< setfill (' ') << setw (0) << dec << endl;
|
||||
cout << "Read e = 8'h" << hex << setw (2) << setfill ('0') << e
|
||||
<< setfill (' ') << setw (0) << dec << endl;
|
||||
cout << "Read f = 8'h" << hex << setw (2) << setfill ('0') << f
|
||||
<< setfill (' ') << setw (0) << dec << endl;
|
||||
cout << endl;
|
||||
#endif
|
||||
|
||||
checkResult ((0 == a) && (0x00 == b) && (0x20 == mem32) && (1 == c)
|
||||
&& (0xff == d) && (0x00 == e) && (0x00 == f),
|
||||
"Bad initial DPI values.");
|
||||
|
||||
// Initialize the clock
|
||||
dut->clk = 0;
|
||||
|
||||
// Check we can read a scalar register.
|
||||
#ifdef TEST_VERBOSE
|
||||
cout << "Test of scalar register reading" << endl;
|
||||
cout << "===============================" << endl;
|
||||
#endif
|
||||
|
||||
for (int i = 0; !Verilated::gotFinish () && (i < 4); i++) {
|
||||
dut->clk = 1 - dut->clk;
|
||||
a = (int) a_read ();
|
||||
logReg (dut->clk, "read a", a, " (before clk)");
|
||||
dut->eval ();
|
||||
|
||||
int a_after = (int) a_read ();
|
||||
logReg (dut->clk, "read a", a_after, " (after clk)");
|
||||
#ifdef TEST_VERBOSE
|
||||
cout << endl;
|
||||
#endif
|
||||
// On a posedge, a should toggle, on a negedge it should stay the
|
||||
// same.
|
||||
checkResult ( ((dut->clk == 1) && (a_after == (1 - a)))
|
||||
|| ((dut->clk == 0) && (a_after == a )),
|
||||
"Test of scalar register reading failed.");
|
||||
}
|
||||
|
||||
checkFinish ("t_dpi_accessors unexpected finish");
|
||||
|
||||
// Check we can read a vector register.
|
||||
#ifdef TEST_VERBOSE
|
||||
cout << "Test of vector register reading" << endl;
|
||||
cout << "===============================" << endl;
|
||||
#endif
|
||||
|
||||
for (int i = 0; !Verilated::gotFinish () && (i < 4); i++) {
|
||||
dut->clk = 1 - dut->clk;
|
||||
b = (int) b_read ();
|
||||
logRegHex (dut->clk, "read b", 8, b, " (before clk)");
|
||||
|
||||
dut->eval ();
|
||||
|
||||
int b_after = (int) b_read ();
|
||||
logRegHex (dut->clk, "read b", 8, b_after, " (after clk)");
|
||||
// b should increment on a posedge and stay the same on a negedge.
|
||||
checkResult ( ((dut->clk == 1) && (b_after == (b + 1)))
|
||||
|| ((dut->clk == 0) && (b_after == b )),
|
||||
"Test of vector register reading failed.");
|
||||
}
|
||||
|
||||
checkFinish ("t_dpi_accessors unexpected finish");
|
||||
|
||||
// Test we can read an array element
|
||||
#ifdef TEST_VERBOSE
|
||||
cout << endl;
|
||||
cout << "Test of array element reading" << endl;
|
||||
cout << "=============================" << endl;
|
||||
#endif
|
||||
|
||||
for (int i = 0; !Verilated::gotFinish () && (i < 4); i++) {
|
||||
dut->clk = 1 - dut->clk;
|
||||
mem32 = (int) mem32_read ();
|
||||
logRegHex (dut->clk, "read mem32", 8, mem32, " (before clk)");
|
||||
|
||||
dut->eval ();
|
||||
|
||||
mem32 = (int) mem32_read ();
|
||||
logRegHex (dut->clk, "read mem32", 8, mem32, " (after clk)");
|
||||
|
||||
// In this case, the value never changes. But we should check it is
|
||||
// waht we expect (0x20).
|
||||
checkResult (mem32 == 0x20, "Test of array element reading failed.");
|
||||
}
|
||||
|
||||
checkFinish ("t_dpi_accessors unexpected finish");
|
||||
|
||||
// Check we can read a scalar wire
|
||||
#ifdef TEST_VERBOSE
|
||||
cout << endl;
|
||||
cout << "Test of scalar wire reading" << endl;
|
||||
cout << "===========================" << endl;
|
||||
#endif
|
||||
|
||||
for (int i = 0; !Verilated::gotFinish () && (i < 4); i++) {
|
||||
dut->clk = 1 - dut->clk;
|
||||
a = (int) a_read ();
|
||||
c = (int) c_read ();
|
||||
logReg (dut->clk, "read a", a, " (before clk)");
|
||||
logReg (dut->clk, "read c", c, " (before clk)");
|
||||
|
||||
dut->eval ();
|
||||
|
||||
a = (int) a_read ();
|
||||
c = (int) c_read ();
|
||||
logReg (dut->clk, "read a", a, " (after clk)");
|
||||
logReg (dut->clk, "read c", c, " (after clk)");
|
||||
// "c" is continuously assigned as the inverse of "a", but in
|
||||
// Verilator, that means that it will only change value when "a"
|
||||
// changes on the posedge of a clock. Put simply, "c" always holds the
|
||||
// inverse of the "after clock" value of "a".
|
||||
checkResult (c == (1 - a), "Test of scalar wire reading failed.");
|
||||
}
|
||||
|
||||
checkFinish ("t_dpi_accessors unexpected finish");
|
||||
|
||||
// Check we can read a vector wire
|
||||
#ifdef TEST_VERBOSE
|
||||
cout << endl;
|
||||
cout << "Test of vector wire reading" << endl;
|
||||
cout << "===========================" << endl;
|
||||
#endif
|
||||
|
||||
for (int i = 0; !Verilated::gotFinish () && (i < 4); i++) {
|
||||
dut->clk = 1 - dut->clk;
|
||||
b = (int) b_read ();
|
||||
d = (int) d_read ();
|
||||
logRegHex (dut->clk, "read b", 8, b, " (before clk)");
|
||||
logRegHex (dut->clk, "read d", 8, d, " (before clk)");
|
||||
|
||||
dut->eval ();
|
||||
|
||||
b = (int) b_read ();
|
||||
d = (int) d_read ();
|
||||
logRegHex (dut->clk, "read b", 8, b, " (after clk)");
|
||||
logRegHex (dut->clk, "read d", 8, d, " (after clk)");
|
||||
|
||||
// "d" is continuously assigned as the (8-bit) bitwise inverse of "b",
|
||||
// but in Verilator, that means that it will only change value when
|
||||
// "b" changes on the posedge of a clock. Put simply, "d" always holds
|
||||
// the inverse of the "after clock" value of "b".
|
||||
checkResult (d == ((~b) & 0xff), "Test of vector wire reading failed.");
|
||||
}
|
||||
|
||||
checkFinish ("t_dpi_accessors unexpected finish");
|
||||
|
||||
// Check we can write a scalar register
|
||||
#ifdef TEST_VERBOSE
|
||||
cout << endl;
|
||||
cout << "Test of scalar register writing" << endl;
|
||||
cout << "===============================" << endl;
|
||||
#endif
|
||||
|
||||
for (int i = 0; !Verilated::gotFinish () && (i < 4); i++) {
|
||||
dut->clk = 1 - dut->clk;
|
||||
a = 1 - (int) a_read ();
|
||||
a_write (a);
|
||||
logReg (dut->clk, "write a", a, " (before clk)");
|
||||
a = a_read ();
|
||||
logReg (dut->clk, "read a", a, " (before clk)");
|
||||
|
||||
dut->eval ();
|
||||
|
||||
int a_after = (int) a_read ();
|
||||
logReg (dut->clk, "read a", a_after, " (after clk)");
|
||||
|
||||
// On a posedge clock, the value of a that is written should toggle,
|
||||
// on a negedge, it should not.
|
||||
checkResult ( ((dut->clk == 1) && (a_after == (1 - a)))
|
||||
|| ((dut->clk == 0) && (a_after == a )),
|
||||
"Test of scalar register writing failed.");
|
||||
}
|
||||
|
||||
checkFinish ("t_dpi_accessors unexpected finish");
|
||||
|
||||
// Check we can write a vector register
|
||||
#ifdef TEST_VERBOSE
|
||||
cout << endl;
|
||||
cout << "Test of vector register writing" << endl;
|
||||
cout << "===============================" << endl;
|
||||
#endif
|
||||
|
||||
for (int i = 0; !Verilated::gotFinish () && (i < 4); i++) {
|
||||
dut->clk = 1 - dut->clk;
|
||||
b = (int) b_read () - 1;
|
||||
b_write ((const svBitVecVal *) &b);
|
||||
logRegHex (dut->clk, "write b", 8, b, " (before clk)");
|
||||
b = (int) b_read ();
|
||||
logRegHex (dut->clk, "read b", 8, b, " (before clk)");
|
||||
|
||||
dut->eval ();
|
||||
|
||||
int b_after = (int) b_read ();
|
||||
logRegHex (dut->clk, "read b", 8, b_after, " (after clk)");
|
||||
|
||||
// The value of "b" written should increment on a posedge and stay the
|
||||
// same on a negedge.
|
||||
checkResult ( ((dut->clk == 1) && (b_after == (b + 1)))
|
||||
|| ((dut->clk == 0) && (b_after == b )),
|
||||
"Test of vector register writing failed.");
|
||||
}
|
||||
|
||||
checkFinish ("t_dpi_accessors unexpected finish");
|
||||
|
||||
// Test we can write an array element
|
||||
#ifdef TEST_VERBOSE
|
||||
cout << endl;
|
||||
cout << "Test of array element writing" << endl;
|
||||
cout << "=============================" << endl;
|
||||
#endif
|
||||
|
||||
for (int i = 0; !Verilated::gotFinish () && (i < 4); i++) {
|
||||
dut->clk = 1 - dut->clk;
|
||||
mem32 = (int) mem32_read () - 1;
|
||||
mem32_write ((const svBitVecVal *) &mem32);
|
||||
logRegHex (dut->clk, "write mem32", 8, mem32, " (before clk)");
|
||||
mem32 = (int) mem32_read ();
|
||||
logRegHex (dut->clk, "read mem32", 8, mem32, " (before clk)");
|
||||
|
||||
dut->eval ();
|
||||
|
||||
int mem32_after = (int) mem32_read ();
|
||||
logRegHex (dut->clk, "read mem32", 8, mem32_after, " (after clk)");
|
||||
|
||||
// In this case, the value we write never changes (this would only
|
||||
// happen if this part of the test coincided with the 32nd element
|
||||
// being overwritten, which it does not. Check that the value after
|
||||
// the clock is the same as before the clock.
|
||||
checkResult (mem32_after == mem32,
|
||||
"Test of array element writing failed.");
|
||||
}
|
||||
|
||||
checkFinish ("t_dpi_accessors unexpected finish");
|
||||
|
||||
// Check we can read a vector register slice
|
||||
#ifdef TEST_VERBOSE
|
||||
cout << endl;
|
||||
cout << "Test of vector register slice reading" << endl;
|
||||
cout << "=====================================" << endl;
|
||||
#endif
|
||||
|
||||
for (int i = 0; !Verilated::gotFinish () && (i < 4); i++) {
|
||||
dut->clk = 1 - dut->clk;
|
||||
b = (int) b_read ();
|
||||
int b_slice = (int) b_slice_read ();
|
||||
logRegHex (dut->clk, "read b [7:0]", 8, b, " (before clk)");
|
||||
logRegHex (dut->clk, "read b [3:0]", 4, b_slice, " (before clk)");
|
||||
|
||||
dut->eval ();
|
||||
|
||||
b = (int) b_read ();
|
||||
b_slice = (int) b_slice_read ();
|
||||
logRegHex (dut->clk, "read b [7:0]", 8, b, " (after clk)");
|
||||
logRegHex (dut->clk, "read b [3:0]", 4, b_slice, " (after clk)");
|
||||
|
||||
// The slice of "b" should always be the bottom 4 bits of "b"
|
||||
checkResult (b_slice == (b & 0x0f),
|
||||
"Test of vector register slice reading failed.");
|
||||
}
|
||||
|
||||
checkFinish ("t_dpi_accessors unexpected finish");
|
||||
|
||||
// Test we can read an array element slice
|
||||
#ifdef TEST_VERBOSE
|
||||
cout << endl;
|
||||
cout << "Test of array element slice reading" << endl;
|
||||
cout << "===================================" << endl;
|
||||
#endif
|
||||
|
||||
for (int i = 0; !Verilated::gotFinish () && (i < 4); i++) {
|
||||
dut->clk = 1 - dut->clk;
|
||||
mem32 = (int) mem32_read ();
|
||||
int mem32_slice = (int) mem32_slice_read ();
|
||||
logRegHex (dut->clk, "read mem32 [7:0] ", 8, mem32, " (before clk)");
|
||||
logRegHex (dut->clk, "read mem32 [7:6,2:0]", 5, mem32_slice,
|
||||
" (before clk)");
|
||||
|
||||
dut->eval ();
|
||||
|
||||
mem32 = (int) mem32_read ();
|
||||
mem32_slice = (int) mem32_slice_read ();
|
||||
logRegHex (dut->clk, "read mem32 [7:0] ", 8, mem32," (after clk)");
|
||||
logRegHex (dut->clk, "read mem32 [7:6,2:0]", 5, mem32_slice,
|
||||
" (after clk)");
|
||||
|
||||
// The slice of "mem32" should always be the concatenation of the top
|
||||
// 2 and bottom 3 bits of "mem32"
|
||||
checkResult (mem32_slice == (((mem32 & 0xc0) >> 3) | (mem32 & 0x07)),
|
||||
"Test of array element slice reading failed.");
|
||||
}
|
||||
|
||||
checkFinish ("t_dpi_accessors unexpected finish");
|
||||
|
||||
// Check we can read a vector wire slice
|
||||
#ifdef TEST_VERBOSE
|
||||
cout << endl;
|
||||
cout << "Test of vector wire slice reading" << endl;
|
||||
cout << "=================================" << endl;
|
||||
#endif
|
||||
|
||||
for (int i = 0; !Verilated::gotFinish () && (i < 4); i++) {
|
||||
dut->clk = 1 - dut->clk;
|
||||
b = (int) b_read ();
|
||||
d = (int) d_read ();
|
||||
int d_slice = (int) d_slice_read ();
|
||||
logRegHex (dut->clk, "read b [7:0]", 8, b, " (before clk)");
|
||||
logRegHex (dut->clk, "read d [7:0]", 8, d, " (before clk)");
|
||||
logRegHex (dut->clk, "read d [6:1]", 6, d_slice, " (before clk)");
|
||||
|
||||
dut->eval ();
|
||||
|
||||
b = (int) b_read ();
|
||||
d = (int) d_read ();
|
||||
d_slice = (int) d_slice_read ();
|
||||
logRegHex (dut->clk, "read b [7:0]", 8, b, " (after clk)");
|
||||
logRegHex (dut->clk, "read d [7:0]", 8, d, " (after clk)");
|
||||
logRegHex (dut->clk, "read d [6:1]", 6, d_slice, " (after clk)");
|
||||
|
||||
// The slice of "d" should always be the middle 6 bits of "d".
|
||||
checkResult (d_slice == ((d & 0x7e) >> 1),
|
||||
"Test of vector wire slice reading failed.");
|
||||
}
|
||||
|
||||
checkFinish ("t_dpi_accessors unexpected finish");
|
||||
|
||||
// Check we can write a vector register slice
|
||||
#ifdef TEST_VERBOSE
|
||||
cout << endl;
|
||||
cout << "Test of vector register slice writing" << endl;
|
||||
cout << "=====================================" << endl;
|
||||
#endif
|
||||
|
||||
for (int i = 0; !Verilated::gotFinish () && (i < 4); i++) {
|
||||
dut->clk = 1 - dut->clk;
|
||||
|
||||
b = (int) b_read ();
|
||||
int b_slice = (int) b_slice_read ();
|
||||
logRegHex (dut->clk, "read b [7:0]", 8, b, " (before write)");
|
||||
logRegHex (dut->clk, "read b [3:0]", 4, b_slice, " (before write)");
|
||||
|
||||
b_slice--;
|
||||
b_slice_write ((const svBitVecVal *) &b_slice);
|
||||
logRegHex (dut->clk, "write b [3:0]", 4, b_slice, " (before clk)");
|
||||
|
||||
int b_after = (int) b_read ();
|
||||
int b_slice_after = (int) b_slice_read ();
|
||||
logRegHex (dut->clk, "read b [7:0]", 8, b_after,
|
||||
" (before clk)");
|
||||
logRegHex (dut->clk, "read b [3:0]", 4, b_slice_after,
|
||||
" (before clk)");
|
||||
|
||||
// We must test that when we wrote the slice of "b", we only wrote the
|
||||
// correct bits. The slice of b is b[3:0]
|
||||
int b_new = (b & 0xf0) | (b_slice &0x0f);
|
||||
checkResult (b_after == b_new,
|
||||
"Test of vector register slice writing failed.");
|
||||
|
||||
dut->eval ();
|
||||
|
||||
b = (int) b_read ();
|
||||
b_slice = (int) b_slice_read ();
|
||||
logRegHex (dut->clk, "read b [7:0]", 8, b, " (after clk)");
|
||||
logRegHex (dut->clk, "read b [3:0]", 4, b_slice, " (after clk)");
|
||||
}
|
||||
|
||||
checkFinish ("t_dpi_accessors unexpected finish");
|
||||
|
||||
// Test we can write an array element slice
|
||||
#ifdef TEST_VERBOSE
|
||||
cout << endl;
|
||||
cout << "Test of array element slice writing" << endl;
|
||||
cout << "===================================" << endl;
|
||||
#endif
|
||||
|
||||
for (int i = 0; !Verilated::gotFinish () && (i < 4); i++) {
|
||||
dut->clk = 1 - dut->clk;
|
||||
|
||||
mem32 = (int) mem32_read ();
|
||||
int mem32_slice = (int) mem32_slice_read ();
|
||||
logRegHex (dut->clk, "read mem32 [7:0] ", 8, mem32,
|
||||
" (before write)");
|
||||
logRegHex (dut->clk, "read mem32 [7:6,2:0]", 5, mem32_slice,
|
||||
" (before write)");
|
||||
|
||||
mem32_slice--;
|
||||
mem32_slice_write ((const svBitVecVal *) &mem32_slice);
|
||||
logRegHex (dut->clk, "write mem32 [7:6,2:0]", 5, mem32_slice,
|
||||
" (before clk)");
|
||||
|
||||
int mem32_after = (int) mem32_read ();
|
||||
int mem32_slice_after = (int) mem32_slice_read ();
|
||||
logRegHex (dut->clk, "read mem32 [7:0] ", 8, mem32_after,
|
||||
" (before clk)");
|
||||
logRegHex (dut->clk, "read mem32 [7:6,2:0]", 5, mem32_slice_after,
|
||||
" (before clk)");
|
||||
|
||||
// We must test that when we wrote the slice of "mem32", we only wrote
|
||||
// the correct bits. The slice of "mem32" is {mem32[7:6], mem32[2:0]}.
|
||||
int mem32_new = (mem32 & 0x38)
|
||||
| ((mem32_slice & 0x18) << 3) |
|
||||
(mem32_slice & 0x7);
|
||||
checkResult (mem32_after == mem32_new,
|
||||
"Test of vector register slice writing failed.");
|
||||
|
||||
dut->eval ();
|
||||
|
||||
mem32 = (int) mem32_read ();
|
||||
mem32_slice = (int) mem32_slice_read ();
|
||||
logRegHex (dut->clk, "read mem32 [7:0] ", 8, mem32," (after clk)");
|
||||
logRegHex (dut->clk, "read mem32 [7:6,2:0]", 5, mem32_slice,
|
||||
" (after clk)");
|
||||
|
||||
// We have already tested that array element writing works, so we just
|
||||
// check that dhe slice of "mem32" after the clock is the
|
||||
// concatenation of the top 2 and bottom 3 bits of "mem32"
|
||||
checkResult (mem32_slice == (((mem32 & 0xc0) >> 3) | (mem32 & 0x07)),
|
||||
"Test of array element slice writing failed.");
|
||||
}
|
||||
|
||||
checkFinish ("t_dpi_accessors unexpected finish");
|
||||
|
||||
// Check we can read complex registers
|
||||
#ifdef TEST_VERBOSE
|
||||
cout << endl;
|
||||
cout << "Test of complex register reading" << endl;
|
||||
cout << "================================" << endl;
|
||||
#endif
|
||||
|
||||
for (int i = 0; !Verilated::gotFinish () && (i < 4); i++) {
|
||||
dut->clk = 1 - dut->clk;
|
||||
|
||||
b = (int) b_read ();
|
||||
mem32 = (int) mem32_read ();
|
||||
e = (int) e_read ();
|
||||
int l1 = (int) l1_read ();
|
||||
logRegHex (dut->clk, "read b ", 8, b, " (before clk)");
|
||||
logRegHex (dut->clk, "read mem32", 8, mem32, " (before clk)");
|
||||
logRegHex (dut->clk, "read e ", 8, e, " (before clk)");
|
||||
logRegHex (dut->clk, "read l1 ", 15, l1, " (before clk)");
|
||||
|
||||
dut->eval ();
|
||||
|
||||
b = (int) b_read ();
|
||||
mem32 = (int) mem32_read ();
|
||||
e = (int) e_read ();
|
||||
l1 = (int) l1_read ();
|
||||
logRegHex (dut->clk, "read b ", 8, b, " (after clk)");
|
||||
logRegHex (dut->clk, "read mem32", 8, mem32, " (after clk)");
|
||||
logRegHex (dut->clk, "read e ", 8, e, " (after clk)");
|
||||
logRegHex (dut->clk, "read l1 ", 15, l1, " (after clk)");
|
||||
|
||||
// We have already tested that reading of registers, memory elements
|
||||
// and wires works. So we just need to check that l1 reads back as the
|
||||
// correct combination of bits after the clock. It should be the 15
|
||||
// bits: {b[3:0],mem[32][7:6],e[6:1],mem[32][2:0]}.
|
||||
checkResult (l1 == ( (((b & 0x0f) >> 0) << 11)
|
||||
| (((mem32 & 0xc0) >> 6) << 9)
|
||||
| (((e & 0x7e) >> 1) << 3)
|
||||
| (((mem32 & 0x07) >> 0) << 0)),
|
||||
"Test of complex register reading l1 failed.");
|
||||
}
|
||||
|
||||
#ifdef TEST_VERBOSE
|
||||
cout << endl;
|
||||
#endif
|
||||
|
||||
checkFinish ("t_dpi_accessors unexpected finish");
|
||||
|
||||
for (int i = 0; !Verilated::gotFinish () && (i < 4); i++) {
|
||||
dut->clk = 1 - dut->clk;
|
||||
|
||||
e = 0x05 | (i << 4);
|
||||
f = 0xa0 | i;
|
||||
e_write ((const svBitVecVal *) &e);
|
||||
f_write ((const svBitVecVal *) &f);
|
||||
|
||||
e = (int) e_read ();
|
||||
f = (int) f_read ();
|
||||
int l2 = (int) l2_read ();
|
||||
logRegHex (dut->clk, "read e ", 8, e, " (before clk)");
|
||||
logRegHex (dut->clk, "read f ", 8, f, " (before clk)");
|
||||
logRegHex (dut->clk, "read l2", 8, l2, " (before clk)");
|
||||
|
||||
dut->eval ();
|
||||
|
||||
e = (int) e_read ();
|
||||
f = (int) f_read ();
|
||||
l2 = (int) l2_read ();
|
||||
logRegHex (dut->clk, "read e ", 8, e, " (before clk)");
|
||||
logRegHex (dut->clk, "read f ", 8, f, " (before clk)");
|
||||
logRegHex (dut->clk, "read l2", 8, l2, " (before clk)");
|
||||
|
||||
// We have already tested that reading of registers, memory elements
|
||||
// and wires works. So we just need to check that l1 reads back as the
|
||||
// correct combination of bits after the clock. It should be the 8
|
||||
// bits: {e[7:4], f[3:0]}.
|
||||
checkResult (l2 == ((e & 0xf0) | (f & 0x0f)),
|
||||
"Test of complex register reading l2 failed.");
|
||||
}
|
||||
|
||||
checkFinish ("t_dpi_accessors unexpected finish");
|
||||
|
||||
// Test we can write a complex register
|
||||
#ifdef TEST_VERBOSE
|
||||
cout << endl;
|
||||
cout << "Test of complex register writing" << endl;
|
||||
cout << "================================" << endl;
|
||||
#endif
|
||||
|
||||
for (int i = 0; !Verilated::gotFinish () && (i < 4); i++) {
|
||||
dut->clk = 1 - dut->clk;
|
||||
|
||||
b = (int) b_read ();
|
||||
mem32 = (int) mem32_read ();
|
||||
e = (int) e_read ();
|
||||
logRegHex (dut->clk, "read b ", 8, b, " (before write)");
|
||||
logRegHex (dut->clk, "read mem32", 8, mem32, " (before write)");
|
||||
logRegHex (dut->clk, "read e ", 8, e, " (before write)");
|
||||
|
||||
int l1 = 0x5a5a;
|
||||
l1_write ((const svBitVecVal *) &l1);
|
||||
logRegHex (dut->clk, "write l1 ", 15, l1, " (before clk)");
|
||||
|
||||
int b_after = (int) b_read ();
|
||||
int mem32_after = (int) mem32_read ();
|
||||
int e_after = (int) e_read ();
|
||||
int l1_after = (int) l1_read ();
|
||||
logRegHex (dut->clk, "read b ", 8, b_after, " (before clk)");
|
||||
logRegHex (dut->clk, "read mem32", 8, mem32_after, " (before clk)");
|
||||
logRegHex (dut->clk, "read e ", 8, e_after, " (before clk)");
|
||||
logRegHex (dut->clk, "read l1 ", 15, l1_after, " (before clk)");
|
||||
|
||||
// We need to check that when we write l1, the correct fields, and
|
||||
// only the correct fields are set in its component registers, wires
|
||||
// and memory elements. l1 is 15 bits:
|
||||
// {b[3:0],mem[32][7:6],e[6:1],mem[32][2:0]}.
|
||||
int b_new = (b & 0xf0) | ((l1 & 0x7800) >> 11);
|
||||
int mem32_new = (mem32 & 0x38) | ((l1 & 0x0600) >> 3) | (l1 & 0x0007);
|
||||
int e_new = (e & 0x81) | ((l1 & 0x01f8) >> 2);
|
||||
checkResult ( (b_new == b_after)
|
||||
&& (mem32_new == mem32_after)
|
||||
&& (e_new == e_after),
|
||||
"Test of complex register writing l1 failed.");
|
||||
|
||||
dut->eval ();
|
||||
|
||||
b = (int) b_read ();
|
||||
mem32 = (int) mem32_read ();
|
||||
d = (int) d_read ();
|
||||
l1 = (int) l1_read ();
|
||||
logRegHex (dut->clk, "read b ", 8, b, " (after clk)");
|
||||
logRegHex (dut->clk, "read mem32", 8, mem32, " (after clk)");
|
||||
logRegHex (dut->clk, "read d ", 8, d, " (after clk)");
|
||||
logRegHex (dut->clk, "read l1 ", 15, l1, " (after clk)");
|
||||
}
|
||||
|
||||
#ifdef TEST_VERBOSE
|
||||
cout << endl;
|
||||
#endif
|
||||
|
||||
checkFinish ("t_dpi_accessors unexpected finish");
|
||||
|
||||
for (int i = 0; !Verilated::gotFinish () && (i < 4); i++) {
|
||||
dut->clk = 1 - dut->clk;
|
||||
|
||||
e = (int) e_read ();
|
||||
f = (int) f_read ();
|
||||
logRegHex (dut->clk, "read e ", 8, e, " (before write)");
|
||||
logRegHex (dut->clk, "read f ", 8, f, " (before write)");
|
||||
|
||||
int l2 = 0xa5 + i;
|
||||
l2_write ((const svBitVecVal *) &l2);
|
||||
logRegHex (dut->clk, "write l2", 8, l2, " (before clk)");
|
||||
|
||||
int e_after = (int) e_read ();
|
||||
int f_after = (int) f_read ();
|
||||
int l2_after = (int) l2_read ();
|
||||
logRegHex (dut->clk, "read e ", 8, e_after, " (before clk)");
|
||||
logRegHex (dut->clk, "read f ", 8, f_after, " (before clk)");
|
||||
logRegHex (dut->clk, "read l2", 8, l2_after, " (before clk)");
|
||||
|
||||
// We need to check that when we write l2, the correct fields, and
|
||||
// only the correct fields are set in its component registers. l is 8
|
||||
// bits: {e[5:2], f[5:2]}
|
||||
int e_new = (e & 0xc3) | ((l2 & 0xf0) >> 2);
|
||||
int f_new = (f & 0xc3) | ((l2 & 0x0f) << 2);
|
||||
checkResult ((e_new == e_after) && (f_new == f_after),
|
||||
"Test of complex register writing l2 failed.");
|
||||
|
||||
dut->eval ();
|
||||
|
||||
e = (int) e_read ();
|
||||
f = (int) f_read ();
|
||||
l2 = (int) l2_read ();
|
||||
logRegHex (dut->clk, "read e ", 8, e, " (before clk)");
|
||||
logRegHex (dut->clk, "read f ", 8, f, " (before clk)");
|
||||
logRegHex (dut->clk, "read l2", 8, l2, " (before clk)");
|
||||
}
|
||||
|
||||
checkFinish ("t_dpi_accessors unexpected finish");
|
||||
|
||||
// Tidy up
|
||||
dut->final ();
|
||||
cout << "*-* All Finished *-*" << endl;;
|
||||
|
||||
} // main ()
|
||||
|
||||
// Local Variables:
|
||||
// c-file-style:"cc-mode"
|
||||
// End:
|
23
test_regress/t/t_dpi_accessors.pl
Executable file
23
test_regress/t/t_dpi_accessors.pl
Executable file
@ -0,0 +1,23 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2012 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.
|
||||
|
||||
# 8-Mar-2012: Modifications for this test contributed by Jeremy Bennett and
|
||||
# Jie Xu.
|
||||
|
||||
compile (
|
||||
make_top_shell => 0,
|
||||
make_main => 0,
|
||||
verilator_flags2 => ["-Wno-BLKANDNBLK -language 1800-2005 --exe $Self->{t_dir}/$Self->{name}.cpp"], );
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
95
test_regress/t/t_dpi_accessors.v
Normal file
95
test_regress/t/t_dpi_accessors.v
Normal file
@ -0,0 +1,95 @@
|
||||
// DESCRIPTION: Verilator: Test for using DPI as general accessors
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2012.
|
||||
//
|
||||
// Contributed by Jeremy Bennett and Jie Xul
|
||||
//
|
||||
// This test exercises the use of DPI to access signals and registers in a
|
||||
// module hierarchy in a uniform fashion. See the discussion at
|
||||
//
|
||||
// http://www.veripool.org/boards/3/topics/show/752-Verilator-Command-line-specification-of-public-access-to-variables
|
||||
//
|
||||
// We need to test read and write access to:
|
||||
// - scalars
|
||||
// - vectors
|
||||
// - array elements
|
||||
// - slices of vectors or array elements
|
||||
//
|
||||
// We need to test that writing to non-writable elements generates an error.
|
||||
//
|
||||
// This Verilog would run forever. It will be stopped externally by the C++
|
||||
// instantiating program.
|
||||
|
||||
|
||||
// Define the width of registers and size of memory we use
|
||||
`define REG_WIDTH 8
|
||||
`define MEM_SIZE 256
|
||||
|
||||
|
||||
// Top module defines the accessors and instantiates a sub-module with
|
||||
// substantive content.
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
input clk;
|
||||
|
||||
`include "t_dpi_accessors_macros_inc.vh"
|
||||
`include "t_dpi_accessors_inc.vh"
|
||||
|
||||
// Put the serious stuff in a sub-module, so we can check hierarchical
|
||||
// access works OK.
|
||||
test_sub i_test_sub (.clk (clk));
|
||||
|
||||
endmodule // t
|
||||
|
||||
|
||||
// A sub-module with all sorts of goodies we would like to access
|
||||
|
||||
module test_sub (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
|
||||
input clk;
|
||||
|
||||
integer i; // General counter
|
||||
|
||||
// Elements we would like to access from outside
|
||||
reg a;
|
||||
reg [`REG_WIDTH - 1:0] b;
|
||||
reg [`REG_WIDTH - 1:0] mem [`MEM_SIZE - 1:0];
|
||||
wire c;
|
||||
wire [`REG_WIDTH - 1:0] d;
|
||||
reg [`REG_WIDTH - 1:0] e;
|
||||
reg [`REG_WIDTH - 1:0] f;
|
||||
|
||||
// Drive our wires from our registers
|
||||
assign c = ~a;
|
||||
assign d = ~b;
|
||||
|
||||
// Initial values for registers and array
|
||||
initial begin
|
||||
a = 0;
|
||||
b = `REG_WIDTH'h0;
|
||||
|
||||
for (i = 0; i < `MEM_SIZE; i++) begin
|
||||
mem[i] = i [`REG_WIDTH - 1:0];
|
||||
end
|
||||
|
||||
e = 0;
|
||||
f = 0;
|
||||
end
|
||||
|
||||
// Wipe out one memory cell in turn on the positive clock edge, restoring
|
||||
// the previous element. We toggle the wipeout value.
|
||||
always @(posedge clk) begin
|
||||
mem[b] <= {`REG_WIDTH {a}};
|
||||
mem[b - 1] <= b - 1;
|
||||
a <= ~a;
|
||||
b <= b + 1;
|
||||
end
|
||||
|
||||
endmodule // test_sub
|
36
test_regress/t/t_dpi_accessors_inc.vh
Normal file
36
test_regress/t/t_dpi_accessors_inc.vh
Normal file
@ -0,0 +1,36 @@
|
||||
// DESCRIPTION: Verilator: Accessor definitions for test of DPI accessors
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2012.
|
||||
|
||||
// Contributed by Jeremy Bennett and Jie Xu
|
||||
|
||||
// See t_dpi_accessors.v for details of the test. This file should be included
|
||||
// by the top level module to define all the accessors needed.
|
||||
|
||||
// Use the macros to provide the desire access to our data. First simple
|
||||
// access to the registers, array elements and wires. For consistency with
|
||||
// simulators, we do not attempt to write wires.
|
||||
`RW_ACCESS ([0:0], a, {t.i_test_sub.a});
|
||||
`RW_ACCESS ([7:0], b, {t.i_test_sub.b});
|
||||
`RW_ACCESS ([7:0], mem32, {t.i_test_sub.mem[32]});
|
||||
`R_ACCESS ([0:0], c, {t.i_test_sub.c});
|
||||
`R_ACCESS ([7:0], d, {t.i_test_sub.d});
|
||||
`RW_ACCESS ([7:0], e, {t.i_test_sub.e});
|
||||
`RW_ACCESS ([7:0], f, {t.i_test_sub.f});
|
||||
|
||||
// Slices of vectors and array elements. For consistency with simulators,
|
||||
// we do not attempt to write wire slices.
|
||||
`RW_ACCESS ([3:0], b_slice, {t.i_test_sub.b[3:0]});
|
||||
`RW_ACCESS ([4:0], mem32_slice,
|
||||
{t.i_test_sub.mem[32][7:6],t.i_test_sub.mem[32][2:0]});
|
||||
`R_ACCESS ([5:0], d_slice, {t.i_test_sub.d[6:1]});
|
||||
|
||||
// Complex registers, one with distinct read and write. We avoid use of
|
||||
// wires for consistency with simulators.
|
||||
`RW_ACCESS ([14:0], l1, {t.i_test_sub.b[3:0],
|
||||
t.i_test_sub.mem[32][7:6],
|
||||
t.i_test_sub.e[6:1],
|
||||
t.i_test_sub.mem[32][2:0]});
|
||||
`R_ACCESS ([7:0], l2, {t.i_test_sub.e[7:4], t.i_test_sub.f[3:0]});
|
||||
`W_ACCESS ([7:0], l2, {t.i_test_sub.e[5:2], t.i_test_sub.f[5:2]});
|
27
test_regress/t/t_dpi_accessors_macros_inc.vh
Normal file
27
test_regress/t/t_dpi_accessors_macros_inc.vh
Normal file
@ -0,0 +1,27 @@
|
||||
// DESCRIPTION: Verilator: Generic accessor macros for test of DPI accessors
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2012.
|
||||
//
|
||||
// Contributed by Jeremy Bennett and Jie Xu
|
||||
//
|
||||
// See t_dpi_accessors.v for details of the test. This file should be included
|
||||
// by the top level module to define the generic accessor macros.
|
||||
|
||||
// Accessor macros, to keep stuff concise
|
||||
`define R_ACCESS(type_spec, name, expr) \
|
||||
export "DPI-C" function name``_read; \
|
||||
function type_spec name``_read; \
|
||||
name``_read = (expr); \
|
||||
endfunction
|
||||
|
||||
`define W_ACCESS(type_spec, name, expr) \
|
||||
export "DPI-C" function name``_write; \
|
||||
task name``_write; \
|
||||
input bit type_spec in; \
|
||||
expr = in; \
|
||||
endtask
|
||||
|
||||
`define RW_ACCESS(type_spec, name, expr) \
|
||||
`R_ACCESS (type_spec, name, expr); \
|
||||
`W_ACCESS (type_spec, name, expr)
|
Loading…
Reference in New Issue
Block a user