1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
|
//
// DESCRIPTION: Verilator: Verilog Multiple Model Test Module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2020-2021 by Andreas Kuster.
// SPDX-License-Identifier: CC0-1.0
//
#include <verilated.h>
#include <verilated_cov.h>
#include <iostream>
#include <thread>
// These require the above. Comment prevents clang-format moving them
#include "TestCheck.h"
#include VM_PREFIX_INCLUDE
// Check we properly define the version integer
#if VERILATOR_VERSION_INTEGER < 4219000 // Added in 4.219
#error "VERILATOR_VERSION_INTEGER not set"
#endif
double sc_time_stamp() { return 0; }
int errors = 0;
VerilatedMutex outputMutex;
#ifdef T_WRAPPER_CONTEXT
#elif defined(T_WRAPPER_CONTEXT_SEQ)
VerilatedMutex sequentialMutex;
#elif defined(T_WRAPPER_CONTEXT_FST)
#else
#error "Unexpected test name"
#endif
void sim(VM_PREFIX* topp) {
#ifdef T_WRAPPER_CONTEXT_SEQ
// Run each sim sequentially
const VerilatedLockGuard seqLock(sequentialMutex);
#endif
VerilatedContext* contextp = topp->contextp();
// This test created a thread, so need to associate VerilatedContext with it
Verilated::threadContextp(contextp);
// reset
topp->clk = 0;
topp->rst = 1;
topp->stop = (topp->trace_number == 0);
topp->eval();
contextp->timeInc(1);
topp->clk = 1;
topp->eval();
contextp->timeInc(1);
topp->rst = 0;
topp->clk = 0;
topp->eval();
// simulate until done
while (!contextp->gotFinish()) {
// increment time
contextp->timeInc(1);
{
const VerilatedLockGuard lock(outputMutex);
#ifdef TEST_VERBOSE
// std::endl needed to flush output before mutex release
std::cout << "{top" << topp->trace_number
<< ", ctx=" << reinterpret_cast<void*>(contextp) << "} [" << contextp->time()
<< "]" << std::endl;
#endif
}
// toggle clk
topp->clk = !topp->clk;
// evaluate model
topp->eval();
}
std::string filename
= std::string{VL_STRINGIFY(TEST_OBJ_DIR) "/coverage_"} + topp->name() + ".dat";
contextp->coveragep()->write(filename.c_str());
}
int main(int argc, char** argv) {
// Create contexts
std::unique_ptr<VerilatedContext> context0p{new VerilatedContext};
std::unique_ptr<VerilatedContext> context1p{new VerilatedContext};
// configuration
context0p->threads(1);
context1p->threads(1);
context0p->fatalOnError(false);
context1p->fatalOnError(false);
context0p->traceEverOn(true);
context1p->traceEverOn(true);
// error number checks
TEST_CHECK_EQ(context0p->errorCount(), 0);
TEST_CHECK_EQ(context1p->errorCount(), 0);
context0p->errorCount(1);
TEST_CHECK_EQ(context0p->errorCount(), 1);
context0p->errorCount(0);
TEST_CHECK_EQ(context0p->errorCount(), 0);
// instantiate verilated design
std::unique_ptr<VM_PREFIX> top0p{new VM_PREFIX{context0p.get(), "top0"}};
std::unique_ptr<VM_PREFIX> top1p{new VM_PREFIX{context1p.get(), "top1"}};
top0p->trace_number = 0;
top0p->trace_number = 1;
std::cout << "Below '%Error: ... Verilog $stop' is expected as part of the test\n";
// create threads
std::thread t0(sim, top0p.get());
std::thread t1(sim, top1p.get());
// wait to finish
t0.join();
t1.join();
// check if both finished
bool pass = true;
if (errors) {
std::cout << "Error: comparison errors" << std::endl;
pass = false;
} else if (top0p->done_o && top1p->done_o) {
std::cout << "*-* All Finished *-*" << std::endl;
} else {
std::cout << "Error: Early termination!" << std::endl;
pass = false;
}
// final model cleanup
top0p->final();
top1p->final();
// exit successful
return pass ? 0 : 10;
}
|