Tests: Add t_dpi_accessors

This commit is contained in:
Wilson Snyder 2012-03-27 20:06:59 -04:00
parent 996f48fcf0
commit aa3a417e97
6 changed files with 912 additions and 0 deletions

1
.gitignore vendored
View File

@ -16,6 +16,7 @@ config.cache
config.status
configure
dddrun*
doxygen-doc
gdbrun*
internals.txt
verilator.pdf

View 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:

View 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;

View 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

View 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]});

View 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)