I am working on a project in SystemC and want to incorporate unit testing. Is it possible to use existing unit test frameworks with SystemC?
I ask this because it seems
Very often SystemC Device-under-test (DUT) can be resetted to initial state by asserting some signal. You can utilize this fact and enable any C++ unit testing framework you want. Just reset you DUT before running each test, so you don't need to elaborate it twice.
Here is an example with Google Test, and a simple "Accumulator" DUT
::testing::InitGoogleTest(&argc, argv);
) from sc_main
sc_module
by calling RUN_ALL_TESTS()
Source:
#include
#include "gtest/gtest.h"
struct test_driver;
test_driver *test_driver_p = nullptr;
void register_test_driver(test_driver *td) {
test_driver_p = td;
}
test_driver* get_test_driver() {
assert(test_driver_p);
return test_driver_p;
}
SC_MODULE(dut_accum) {
sc_in_clk clk{"clk"};
sc_in reset{"reset"};
sc_in en{"en"};
sc_in din{"din"};
sc_out dout{"dout"};
SC_CTOR(dut_accum) {
SC_METHOD(accum_method);
sensitive << clk.pos();
};
void accum_method() {
if (reset)
dout = 0;
else if (en)
dout = dout + din;
}
};
SC_MODULE(test_driver) {
sc_signal reset{"reset",1};
sc_signal en{"en",0};
sc_signal din{"din",0};
sc_signal dout{"dout"};
SC_CTOR(test_driver) {
dut_inst.clk(clk);
dut_inst.reset(reset);
dut_inst.en(en);
dut_inst.din(din);
dut_inst.dout(dout);
SC_THREAD(test_thread);
sensitive << clk.posedge_event();
register_test_driver(this);
}
private:
void test_thread() {
if (RUN_ALL_TESTS())
SC_REPORT_ERROR("Gtest", "Some test FAILED");
sc_stop();
}
dut_accum dut_inst{"dut_inst"};
sc_clock clk{"clk", 10, SC_NS};
};
namespace {
// The fixture for testing dut_accum
class accum_test: public ::testing::Test {
protected:
test_driver & td;
accum_test(): td(*get_test_driver()){
reset_dut();
}
virtual ~accum_test() {}
void reset_dut(){
td.reset = 1;
wait();
td.reset = 0;
}
};
TEST_F(accum_test, test0) {
td.din = 10;
td.en = 1;
wait();
wait();
EXPECT_EQ(td.dout.read(), 10);
}
TEST_F(accum_test, test1_no_en) {
td.din = 10;
td.en = 0;
wait();
wait();
EXPECT_EQ(td.dout.read(), 10); // this test will fail, since en is 0
}
TEST_F(accum_test, test2_reset_asserted) {
td.din = 10;
td.en = 1;
td.reset = 1;
wait();
wait();
EXPECT_EQ(td.dout.read(), 0);
}
}
int sc_main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
test_driver td{"td"};
sc_start();
}
CMakeLists.txt (requires installed SystemC 2.3.2 )
cmake_minimum_required(VERSION 3.8)
project(systemc_gtest)
find_package(SystemCLanguage CONFIG REQUIRED)
set (CMAKE_CXX_STANDARD ${SystemC_CXX_STANDARD})
find_package(GTest REQUIRED)
enable_testing()
add_executable(systemc_gtest main.cpp)
target_link_libraries(systemc_gtest ${GTEST_LIBRARIES} SystemC::systemc )
target_include_directories(systemc_gtest PRIVATE ${GTEST_INCLUDE_DIRS})
add_test(AllTestsInSystemCGtest systemc_gtest)