mirror of
https://github.com/verilator/verilator.git
synced 2025-02-07 14:11:49 +00:00
This patch normalizes what the tests do before exiting. After this change each test should call final on the top module and explicitly free the top module object before exiting.
683 lines
25 KiB
C++
683 lines
25 KiB
C++
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
|
//*************************************************************************
|
|
//
|
|
// 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.
|
|
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
|
//
|
|
// 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);
|
|
}
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
// 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); }
|
|
}
|
|
|
|
// Main function instantiates the model and steps through the test.
|
|
int main() {
|
|
Vt_dpi_accessors* dut = new Vt_dpi_accessors("dut");
|
|
svScope scope = svGetScopeFromName("dut.t");
|
|
if (!scope) vl_fatal(__FILE__, __LINE__, "dut", "No svGetScopeFromName result");
|
|
svSetScope(scope);
|
|
|
|
// 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(reinterpret_cast<const svBitVecVal*>(&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(reinterpret_cast<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(reinterpret_cast<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(reinterpret_cast<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(reinterpret_cast<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(reinterpret_cast<const svBitVecVal*>(&e));
|
|
f_write(reinterpret_cast<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(reinterpret_cast<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(reinterpret_cast<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();
|
|
VL_DO_DANGLING(delete dut, dut);
|
|
cout << "*-* All Finished *-*" << endl;
|
|
}
|
|
|
|
// Local Variables:
|
|
// c-file-style:"cc-mode"
|
|
// End:
|