diff --git a/.cproject b/.cproject index 5484523..6826073 100644 --- a/.cproject +++ b/.cproject @@ -28,10 +28,9 @@ - - + + - @@ -64,10 +63,9 @@ - - + + - @@ -99,12 +97,47 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -117,10 +150,12 @@ + + diff --git a/.gitignore b/.gitignore index af81461..ffab976 100644 --- a/.gitignore +++ b/.gitignore @@ -47,3 +47,4 @@ /.direnv/ /.venv/ /.cache +/CMakeUserPresets.json diff --git a/.gitmodules b/.gitmodules index 6211793..1ddda03 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "scc"] path = scc url = https://github.com/Minres/SystemC-Components.git +[submodule "cmake-conan"] + path = cmake-conan + url = https://github.com/conan-io/cmake-conan.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 808a583..30fb7c7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,11 +8,9 @@ option(FULL_TEST_SUITE "enable also long-running tests" OFF) option(ENABLE_SCV "Enable use of SCV" OFF) option(ENABLE_CLANG_TIDY "Enable clang-tidy checks" OFF) -include(ConanInline) include(GNUInstallDirs) include(BuildType) -set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_POSITION_INDEPENDENT_CODE ON) @@ -20,14 +18,6 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON) include(CheckCXXCompilerFlag) CHECK_CXX_COMPILER_FLAG("-march=native" COMPILER_SUPPORTS_MARCH_NATIVE) -if(COMPILER_SUPPORTS_MARCH_NATIVE) - if("${CMAKE_BUILD_TYPE}" STREQUAL "") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native") - elseif(NOT(${CMAKE_BUILD_TYPE} STREQUAL "RelWithDebInfo")) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native") - endif() -endif() - if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") set(warnings "-Wall -Wextra -Werror") set(CMAKE_CXX_FLAG_RELEASE "-O3 -DNDEBUG") @@ -39,11 +29,10 @@ endif() if(ENABLE_COVERAGE) include(CodeCoverage) append_coverage_compiler_flags() - set(COVERAGE_EXCLUDES "osci-lib/scc/*" "/engr/dev/tools/*") endif() -find_program(CLANG_TIDY_EXE NAMES "clang-tidy") if(ENABLE_CLANG_TIDY) + find_program(CLANG_TIDY_EXE NAMES "clang-tidy") if(CLANG_TIDY_EXE) message(STATUS "clang-tidy found: ${CLANG_TIDY_EXE}") #set(CLANG_TIDY_CHECKS "-*,modernize-*,-modernize-use-trailing-return-type,clang-analyzer-core.*,clang-analyzer-cplusplus.*") @@ -54,17 +43,8 @@ if(ENABLE_CLANG_TIDY) endif() endif() -set(CLANG_FORMAT_EXCLUDE_PATTERNS "/third_party/") +set(CLANG_FORMAT_EXCLUDE_PATTERNS "/third_party/" "/build/") find_package(ClangFormat) - -set(CONAN_CMAKE_SILENT_OUTPUT ON) -conan_check() -conan_configure(REQUIRES jsoncpp/1.9.5 yaml-cpp/0.6.3 spdlog/1.9.2 fmt/8.0.1 boost/1.85.0 gsl-lite/0.37.0 systemc/2.3.4 catch2/3.1.0 zlib/1.2.11 lz4/1.9.4 - GENERATORS cmake_find_package - OPTIONS fmt:header_only=True spdlog:header_only=True - ) -conan_install() - find_package(ZLIB) find_package(lz4) # This line finds the boost lib and headers. diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 0000000..86840c3 --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,40 @@ +{ + "version": 3, + "vendor": { + "conan": {} + }, + "cmakeMinimumRequired": { + "major": 3, + "minor": 24, + "patch": 0 + }, + "configurePresets": [ + { + "name": "Debug", + "cacheVariables": { + "CMAKE_POLICY_DEFAULT_CMP0091": "NEW", + "CMAKE_BUILD_TYPE": "Debug", + "CMAKE_CXX_STANDARD": "17", + "CMAKE_PROJECT_TOP_LEVEL_INCLUDES": "cmake-conan/conan_provider.cmake" + } + }, + { + "name": "RelWithDebInfo", + "cacheVariables": { + "CMAKE_POLICY_DEFAULT_CMP0091": "NEW", + "CMAKE_BUILD_TYPE": "RelWithDebInfo", + "CMAKE_CXX_STANDARD": "17", + "CMAKE_PROJECT_TOP_LEVEL_INCLUDES": "cmake-conan/conan_provider.cmake" + } + }, + { + "name": "Release", + "cacheVariables": { + "CMAKE_POLICY_DEFAULT_CMP0091": "NEW", + "CMAKE_BUILD_TYPE": "Release", + "CMAKE_CXX_STANDARD": "17", + "CMAKE_PROJECT_TOP_LEVEL_INCLUDES": "cmake-conan/conan_provider.cmake" + } + } + ] +} \ No newline at end of file diff --git a/Jenkinsfile b/Jenkinsfile index fa67378..d9dbfe3 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -29,18 +29,12 @@ void checkout_project() { ]) } -void setup_conan() { - sh''' - pip3 install --user "conan<2.0" pyucis - conan profile new default --detect --force - conan remote list | grep minres > /dev/null - [ $? ] || conan remote add minres https://git.minres.com/api/packages/Tooling/conan - ''' -} - void build_n_test_project() { sh''' - cmake -S . -B build + python3 -mvenv .venv + . .venv/bin/activate + pip3 install -r requirements.txt + cmake -S . -B build --preset Release cmake --build build -j12 cmake --build build --target test ''' @@ -57,47 +51,30 @@ pipeline { stages { stage('SCC test pipeline') { parallel { - stage('U22.04') { + stage('ubuntu-22.04') { agent {docker { image 'ubuntu-22.04' } } stages { stage('Checkout') { steps { checkout_project() }} - stage('Setup') { steps { setup_conan() }} stage('Build & test') { steps { build_n_test_project() }} } } - stage('U20.04') { - agent {docker { image 'ubuntu-20.04' } } - stages { - stage('Checkout') { steps { checkout_project() }} - stage('Setup') { steps { setup_conan() }} - stage('Build & test') { steps { build_n_test_project() }} - } - } - stage('COS7') { - agent {docker { image 'centos7' } } - stages { - stage('Checkout') { steps { checkout_project() }} - stage('Setup') { steps { setup_conan() }} - stage('Build & test') { steps { build_n_test_project() }} - } - } - stage('RCK8') { + stage('rockylinux8') { agent {docker { image 'rockylinux8' } } stages { stage('Checkout') { steps { checkout_project() }} - stage('Setup') { steps { setup_conan() }} stage('Build & test') { steps { build_n_test_project() }} } } - // stage('Format check') { - agent {docker { image 'ubuntu-riscv' } } + agent {docker { image 'ubuntu-22.04' } } stages { stage('Checkout') { steps { checkout_project() }} - stage('Setup') { steps { setup_conan() }} stage('Build & check format') { steps { sh''' - cmake -S . -B build + python3 -mvenv .venv + . .venv/bin/activate + pip3 install -r requirements.txt + cmake -S . -B build --preset Release cmake --build build --target format-check ''' }} diff --git a/Modulefile b/Modulefile index 5d602fb..4891e78 100644 --- a/Modulefile +++ b/Modulefile @@ -13,5 +13,5 @@ if { $distro == "CentOS" && ![info exists ::env(PROJECT)] && ![info exists ::env } module load tools/utilities -module load tools/cmake +module load tools/cmake/3.28 module load tools/clang/14.0 diff --git a/README.md b/README.md index 171f11e..98bb81b 100644 --- a/README.md +++ b/README.md @@ -12,9 +12,10 @@ In Console: module load ./Modulefile python3 -mvenv .venv . .venv/bin/activate - pip3 install conan==1.59.0 - cmake -S . -B build + pip3 install -r requirements.txt + cmake -S . -B build --preset Release cmake --build build -j30 + cmake --build build --target test \ No newline at end of file diff --git a/cmake-conan b/cmake-conan new file mode 160000 index 0000000..c22bbf0 --- /dev/null +++ b/cmake-conan @@ -0,0 +1 @@ +Subproject commit c22bbf0af0b73d5f0def24a9cdf4ce503ae79e5d diff --git a/conanfile.txt b/conanfile.txt new file mode 100644 index 0000000..80c687f --- /dev/null +++ b/conanfile.txt @@ -0,0 +1,44 @@ +[requires] +jsoncpp/1.9.5 +yaml-cpp/0.6.3 +spdlog/1.9.2 +fmt/8.0.1 +boost/1.85.0 +gsl-lite/0.37.0 +systemc/2.3.4 +catch2/3.1.0 +zlib/1.2.11 +lz4/1.9.4 +rapidjson/cci.20230929 + +[options] +boost/*:fPIC=True +boost/*:header_only=False +boost/*:without_contract=True +boost/*:without_fiber=True +boost/*:without_graph=True +boost/*:without_graph_parallel=True +boost/*:without_iostreams=True +boost/*:without_json=True +boost/*:without_locale=True +boost/*:without_log=True +boost/*:without_math=True +boost/*:without_mpi=True +boost/*:without_nowide=True +boost/*:without_python=True +boost/*:without_random=True +boost/*:without_regex=True +boost/*:without_stacktrace=True +boost/*:without_test=True +boost/*:without_timer=True +boost/*:without_type_erasure=True +boost/*:without_wave=True +systemc/*:shared=False +systemc/*:disable_virtual_bind=False + +[generators] +CMakeDeps +CMakeToolchain + +[layout] +cmake_layout diff --git a/examples/ahb_bfm/sc_main.cpp b/examples/ahb_bfm/sc_main.cpp deleted file mode 100644 index b01ad27..0000000 --- a/examples/ahb_bfm/sc_main.cpp +++ /dev/null @@ -1,148 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace sc_core; -using namespace scc; - -class testbench : public sc_module, public scc::traceable { -public: - enum { WIDTH = 64 }; - tlm::scc::initiator_mixin> isck{"isck"}; - ahb::pin::initiator intor{"intor"}; - sc_core::sc_clock HCLK{"HCLK", 10_ns}; - sc_core::sc_signal HRESETn{"HRESETn"}; - sc_core::sc_signal> HADDR{"HADDR"}; - sc_core::sc_signal> HBURST{"HBURST"}; - sc_core::sc_signal HMASTLOCK{"HMASTLOCK"}; - sc_core::sc_signal> HPROT{"HPROT"}; - sc_core::sc_signal> HSIZE{"HSIZE"}; - sc_core::sc_signal> HTRANS{"HTRANS"}; - sc_core::sc_signal> HWDATA{"HWDATA"}; - sc_core::sc_signal HWRITE{"HWRITE"}; - sc_core::sc_signal> HRDATA{"HRDATA"}; - sc_core::sc_signal HREADY{"HREADY"}; - sc_core::sc_signal HRESP{"HRESP"}; - sc_core::sc_signal HSEL{"HSEL"}; - - ahb::pin::target target{"target"}; - tlm::scc::target_mixin> tsck{"tsck"}; - - testbench(sc_module_name nm) - : sc_module(nm) { - SC_HAS_PROCESS(testbench); - isck(intor.tsckt); - intor.HCLK_i(HCLK); - intor.HRESETn_i(HRESETn); - intor.HADDR_o(HADDR); - intor.HBURST_o(HBURST); - intor.HMASTLOCK_o(HMASTLOCK); - intor.HPROT_o(HPROT); - intor.HSIZE_o(HSIZE); - intor.HTRANS_o(HTRANS); - intor.HWDATA_o(HWDATA); - intor.HWRITE_o(HWRITE); - intor.HRDATA_i(HRDATA); - intor.HREADY_i(HREADY); - intor.HRESP_i(HRESP); - target.HCLK_i(HCLK); - target.HRESETn_i(HRESETn); - target.HADDR_i(HADDR); - target.HBURST_i(HBURST); - target.HMASTLOCK_i(HMASTLOCK); - target.HPROT_i(HPROT); - target.HSIZE_i(HSIZE); - target.HTRANS_i(HTRANS); - target.HWDATA_i(HWDATA); - target.HWRITE_i(HWRITE); - target.HSEL_i(HSEL); - target.HRDATA_o(HRDATA); - target.HREADY_o(HREADY); - target.HRESP_o(HRESP); - target.isckt(tsck); - SC_THREAD(run); - tsck.register_b_transport([this](tlm::tlm_generic_payload& gp, sc_time& delay) { - gp.set_response_status(tlm::TLM_OK_RESPONSE); - if(gp.is_write()) { - SCCINFO(SCMOD) << "Received write access to addr 0x" << std::hex << gp.get_address(); - } else { - memset(gp.get_data_ptr(), 0x55, gp.get_data_length()); - SCCINFO(SCMOD) << "Received read access from addr 0x" << std::hex << gp.get_address(); - } - }); - } - - void run() { - HRESETn.write(false); - for(size_t i = 0; i < 10; ++i) - wait(HCLK.posedge_event()); - HRESETn.write(true); - wait(HCLK.posedge_event()); - HSEL.write(true); - tlm::tlm_generic_payload gp; - uint8_t data[8]; - data[0] = 2; - data[1] = 4; - gp.set_address(0x1000); - gp.set_data_length(8); - gp.set_data_ptr(data); - gp.set_streaming_width(8); - gp.set_command(tlm::TLM_WRITE_COMMAND); - sc_time delay; - isck->b_transport(gp, delay); - gp.set_address(0x1020); - gp.set_data_length(8); - gp.set_data_ptr(data); - gp.set_streaming_width(8); - gp.set_command(tlm::TLM_READ_COMMAND); - delay = SC_ZERO_TIME; - isck->b_transport(gp, delay); - for(size_t i = 0; i < 10; ++i) - wait(HCLK.posedge_event()); - sc_stop(); - } -}; - -int sc_main(int argc, char* argv[]) { - sc_core::sc_report_handler::set_actions("/IEEE_Std_1666/deprecated", sc_core::SC_DO_NOTHING); - sc_report_handler::set_actions(SC_ID_MORE_THAN_ONE_SIGNAL_DRIVER_, SC_DO_NOTHING); - /////////////////////////////////////////////////////////////////////////// - // configure logging - /////////////////////////////////////////////////////////////////////////// - scc::init_logging(scc::log::DEBUG); - /////////////////////////////////////////////////////////////////////////// - // set up configuration and tracing - /////////////////////////////////////////////////////////////////////////// - scc::configurer cfg("ahb_bfm.json"); - scc::configurable_tracer trace("ahb_bfm", tracer::TEXT, true, true); - /////////////////////////////////////////////////////////////////////////// - // create modules/channels and trace - /////////////////////////////////////////////////////////////////////////// - testbench tb("tb"); - trace.add_control(); - { - std::ofstream of{"ahb_test.default.json"}; - if(of.is_open()) - cfg.dump_configuration(of); - } - cfg.configure(); - /////////////////////////////////////////////////////////////////////////// - // run the simulation - /////////////////////////////////////////////////////////////////////////// - try { - sc_core::sc_start(1_us); - if(!sc_core::sc_end_of_simulation_invoked()) - sc_core::sc_stop(); - } catch(sc_core::sc_report& rep) { - sc_core::sc_report_handler::get_handler()(rep, sc_core::SC_DISPLAY | sc_core::SC_STOP); - } - return 0; -} diff --git a/requirements.txt b/requirements.txt index f5ad00c..b7d8b70 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,3 @@ -conan<2.0 +conan>=2.0 +cmake +clang-format==14.0 \ No newline at end of file diff --git a/scc b/scc index 4f27c76..bccc926 160000 --- a/scc +++ b/scc @@ -1 +1 @@ -Subproject commit 4f27c76e0631da96cfdf421e91c2cd983c3f4253 +Subproject commit bccc9269ff84181d1287dd6021ab5eb52f8909d0 diff --git a/src/factory.h b/src/factory.h index 2c57fce..09e8cb3 100644 --- a/src/factory.h +++ b/src/factory.h @@ -25,7 +25,7 @@ public: add(const std::string& name, Args&&... args); }; - template static T& get(const std::string& name = ""); + template static T& get(const std::string& name = typeid(T).name()); void create(); @@ -50,7 +50,7 @@ private: std::map m_objects; }; -template factory::add::add(Args&&... args) { add("", args...); } +template factory::add::add(Args&&... args) { add(typeid(T).name(), args...); } template factory::add::add(const std::string& name, Args&&... args) { factory::get_instance().add_object(name, [args...]() -> object { diff --git a/src/sc_main.cpp b/src/sc_main.cpp index 6ff5088..b1fe425 100644 --- a/src/sc_main.cpp +++ b/src/sc_main.cpp @@ -24,11 +24,14 @@ void ABRThandler(int sig) { longjmp(abrt, 1); } int sc_main(int argc, char* argv[]) { signal(SIGABRT, ABRThandler); auto my_name = util::split(argv[0], '/').back(); - scc::init_logging(LogConfig().logLevel(getenv("SCC_TEST_VERBOSE") ? log::TRACE : log::FATAL).logAsync(false).msgTypeFieldWidth(35)); + auto level = getenv("SCC_TEST_VERBOSE"); + auto log_lvl = level ? static_cast(std::min(strtoul(level, nullptr, 10) + 4, 7UL)) : log::FATAL; + scc::init_logging(LogConfig().logLevel(log_lvl).logAsync(false).msgTypeFieldWidth(35)); // create tracer if environment variable SCC_TEST_TRACE is defined std::unique_ptr tracer; - if(getenv("SCC_TEST_TRACE")) - tracer = std::make_unique(my_name, scc::tracer::NONE, scc::tracer::ENABLE); + if(auto* test_trace = getenv("SCC_TEST_TRACE")) { + tracer = std::make_unique(my_name, scc::tracer::ENABLE, scc::tracer::ENABLE); + } int result = -1; if(setjmp(abrt) == 0) { // instantiate design(s) @@ -37,6 +40,7 @@ int sc_main(int argc, char* argv[]) { result = Catch::Session().run(argc, argv); // destroy design(s) sc_stop(); + SCCTRACE() << "Test sequence finished"; factory::get_instance().destroy(); } return result; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 5e98656..7004527 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,11 +1,14 @@ add_subdirectory(io-redirector) add_subdirectory(ordered_semaphore) add_subdirectory(cci_param_restricted) +add_subdirectory(apb_pin_level) add_subdirectory(ahb_pin_level) add_subdirectory(axi4_pin_level) add_subdirectory(ace_pin_level) add_subdirectory(configuration) add_subdirectory(configurer) +add_subdirectory(sc_fixed_tracing) +add_subdirectory(cxs_tlm) if(FULL_TEST_SUITE) add_subdirectory(sim_performance) endif() diff --git a/tests/apb_pin_level/CMakeLists.txt b/tests/apb_pin_level/CMakeLists.txt new file mode 100644 index 0000000..bd52313 --- /dev/null +++ b/tests/apb_pin_level/CMakeLists.txt @@ -0,0 +1,9 @@ +project (apb_pin_level) + +add_executable(${PROJECT_NAME} + bus_test.cpp + ${test_util_SOURCE_DIR}/sc_main.cpp +) +target_link_libraries (${PROJECT_NAME} PUBLIC test_util) + +catch_discover_tests(${PROJECT_NAME}) diff --git a/tests/apb_pin_level/bus_test.cpp b/tests/apb_pin_level/bus_test.cpp new file mode 100644 index 0000000..3cdff2f --- /dev/null +++ b/tests/apb_pin_level/bus_test.cpp @@ -0,0 +1,255 @@ + +#include "testbench.h" +#include +#include +#undef CHECK +#include +#include + +using namespace sc_core; +using namespace ahb; + +factory::add tb; +bool is_equal(tlm::tlm_generic_payload const& a, tlm::tlm_generic_payload const& b) { + auto ret = true; + ret &= a.get_command() == b.get_command(); + ret &= a.get_address() == b.get_address(); + ret &= a.get_data_length() == b.get_data_length(); + for(auto i = 0u; i < a.get_data_length(); ++i) + ret &= a.get_data_ptr()[i] == b.get_data_ptr()[i]; + // if(a.get_byte_enable_ptr() && b.get_byte_enable_ptr()) { + // ret &= a.get_byte_enable_length() == b.get_byte_enable_length(); + // for(auto i=0u; i tlm::tlm_generic_payload* prepare_trans(uint64_t start_address, unsigned len, unsigned width) { + static unsigned id{0}; + auto trans = tlm::scc::tlm_mm<>::get().allocate(len); + trans->set_address(start_address); + tlm::scc::setId(*trans, ++id); + auto ext = trans->get_extension(); + trans->set_data_length(len); + trans->set_streaming_width(len); + ext->set_instruction(); + return trans; +} + +inline void randomize(tlm::tlm_generic_payload& gp) { + static uint8_t req_cnt{0}; + for(size_t i = 0; i < gp.get_data_length(); ++i) { + *(gp.get_data_ptr() + i) = i % 2 ? i : req_cnt; + } + req_cnt++; +} + +template unsigned run_scenario(STATE& state, unsigned wait_states = 0) { + auto& dut = factory::get(); + dut.register_b_transport([&state, wait_states](tlm::tlm_base_protocol_types::tlm_payload_type& trans, sc_core::sc_time& d) { + if(trans.is_read()) { + for(size_t i = 0; i < trans.get_data_length(); ++i) { + *(trans.get_data_ptr() + i) = i % 2 ? i : (state.resp_cnt + 128); + } + state.read_tx.second.emplace_back(&trans); + } + if(trans.is_write()) + state.write_tx.second.emplace_back(&trans); + SCCDEBUG(__FUNCTION__) << "RX: " << trans; + for(unsigned i = 0; i < wait_states; ++i) + sc_core::wait(factory::get().clk.posedge_event()); + state.resp_cnt++; + trans.set_response_status(tlm::TLM_OK_RESPONSE); + }); + + dut.rst_n.write(false); + sc_start(state.ResetCycles * dut.clk.period()); + dut.rst_n.write(true); + sc_start(dut.clk.period()); + sc_start(dut.clk.period()); + + auto run1 = sc_spawn([&dut, &state]() { + unsigned int StartAddr{0x0}; + for(int i = 0; i < state.NumberOfIterations; ++i) { + tlm::scc::tlm_gp_shared_ptr trans = + prepare_trans(StartAddr, state.BurstLengthByte, state.BurstSizeBytes); + trans->set_command(tlm::TLM_READ_COMMAND); + SCCDEBUG(__FUNCTION__) << "task run1, iteration " << i << " TX: " << *trans; + sc_core::sc_time d; + dut.isck->b_transport(*trans, d); + state.read_tx.first.emplace_back(trans); + StartAddr += state.BurstSizeBytes; + } + SCCDEBUG(__FUNCTION__) << "task run1 finished"; + }); + auto run2 = sc_spawn([&dut, &state]() { + unsigned int StartAddr{0x2000}; + for(int i = 0; i < state.NumberOfIterations; ++i) { + tlm::scc::tlm_gp_shared_ptr trans = + prepare_trans(StartAddr, state.BurstLengthByte, state.BurstSizeBytes); + trans->set_command(tlm::TLM_WRITE_COMMAND); + randomize(*trans); + SCCDEBUG(__FUNCTION__) << "task run2, iteration " << i << " TX: " << *trans; + sc_core::sc_time d; + dut.isck->b_transport(*trans, d); + state.write_tx.first.emplace_back(trans); + StartAddr += state.BurstSizeBytes; + } + SCCDEBUG(__FUNCTION__) << "task run2 finished"; + }); + auto run3 = sc_spawn([&dut, &state]() { + unsigned int StartAddr{0x1000}; + for(int i = 0; i < state.NumberOfIterations; ++i) { + tlm::scc::tlm_gp_shared_ptr trans = + prepare_trans(StartAddr, state.BurstLengthByte, state.BurstSizeBytes); + trans->set_command(tlm::TLM_READ_COMMAND); + SCCDEBUG(__FUNCTION__) << "task run3, iteration " << i << " TX: " << *trans; + sc_core::sc_time d; + dut.isck->b_transport(*trans, d); + state.read_tx.first.emplace_back(trans); + StartAddr += state.BurstSizeBytes; + } + SCCDEBUG(__FUNCTION__) << "task run3 finished"; + }); + auto run4 = sc_spawn([&dut, &state]() { + unsigned int StartAddr{0x3000}; + for(int i = 0; i < state.NumberOfIterations; ++i) { + tlm::scc::tlm_gp_shared_ptr trans = + prepare_trans(StartAddr, state.BurstLengthByte, state.BurstSizeBytes); + trans->set_command(tlm::TLM_WRITE_COMMAND); + randomize(*trans); + SCCDEBUG(__FUNCTION__) << "task run4, iteration " << i << " TX: " << *trans; + sc_core::sc_time d; + dut.isck->b_transport(*trans, d); + state.write_tx.first.emplace_back(trans); + StartAddr += state.BurstSizeBytes; + } + SCCDEBUG(__FUNCTION__) << "task run4 finished"; + }); + + unsigned cycles{0}; + while(cycles < 1000 && !(run1.terminated() && run2.terminated() && run3.terminated() && run4.terminated())) { + sc_start(10 * dut.clk.period()); + cycles += 10; + } + return cycles; +} + +TEST_CASE("apb_read_write", "[APB][pin-level]") { + struct { + unsigned int ResetCycles{4}; + unsigned int BurstLengthByte{4}; + unsigned int BurstSizeBytes{4}; + unsigned int NumberOfIterations{1}; + std::pair, std::vector> read_tx; + std::pair, std::vector> write_tx; + unsigned resp_cnt{0}; + } state; + + auto cycles = run_scenario(state); + + REQUIRE(cycles < 1000); + REQUIRE(sc_report_handler::get_count(SC_ERROR) == 0); + REQUIRE(sc_report_handler::get_count(SC_WARNING) == 0); + + REQUIRE(state.resp_cnt == 4 * state.NumberOfIterations); + { + auto& e = state.write_tx; + auto const& send_tx = e.first; + auto const& recv_tx = e.second; + REQUIRE(send_tx.size() == recv_tx.size()); + for(auto i = 0; i < send_tx.size(); ++i) { + REQUIRE(send_tx[i]->get_response_status() == tlm::TLM_OK_RESPONSE); + CHECK(is_equal(*send_tx[i], *recv_tx[i])); + } + } + { + auto& e = state.read_tx; + auto const& send_tx = e.first; + auto const& recv_tx = e.second; + REQUIRE(send_tx.size() == recv_tx.size()); + for(auto i = 0; i < send_tx.size(); ++i) { + REQUIRE(send_tx[i]->get_response_status() == tlm::TLM_OK_RESPONSE); + CHECK(is_equal(*send_tx[i], *recv_tx[i])); + } + } +} + +TEST_CASE("apb_narrow_read_write", "[APB][pin-level]") { + struct { + unsigned int ResetCycles{4}; + unsigned int BurstLengthByte{1}; + unsigned int BurstSizeBytes{1}; + unsigned int NumberOfIterations{8}; + std::pair, std::vector> read_tx; + std::pair, std::vector> write_tx; + unsigned resp_cnt{0}; + } state; + + auto cycles = run_scenario(state); + + REQUIRE(cycles < 1000); + REQUIRE(sc_report_handler::get_count(SC_ERROR) == 0); + REQUIRE(sc_report_handler::get_count(SC_WARNING) == 0); + + REQUIRE(state.resp_cnt == 4 * state.NumberOfIterations); + { + auto& e = state.write_tx; + auto const& send_tx = e.first; + auto const& recv_tx = e.second; + REQUIRE(send_tx.size() == recv_tx.size()); + for(auto i = 0; i < send_tx.size(); ++i) + CHECK(is_equal(*send_tx[i], *recv_tx[i])); + } + { + auto& e = state.read_tx; + auto const& send_tx = e.first; + auto const& recv_tx = e.second; + REQUIRE(send_tx.size() == recv_tx.size()); + // Narrow reads cannot be checked as they arrive a word read at the target + // for(auto i = 0; i < send_tx.size(); ++i) + // CHECK(is_equal(*send_tx[i], *recv_tx[i])); + } +} + +TEST_CASE("apb_delayed_read_write", "[APB][pin-level]") { + struct { + unsigned int ResetCycles{4}; + unsigned int BurstLengthByte{4}; + unsigned int BurstSizeBytes{4}; + unsigned int NumberOfIterations{2}; + std::pair, std::vector> read_tx; + std::pair, std::vector> write_tx; + unsigned resp_cnt{0}; + } state; + + auto cycles = run_scenario(state, 2); + + REQUIRE(cycles < 1000); + REQUIRE(sc_report_handler::get_count(SC_ERROR) == 0); + REQUIRE(sc_report_handler::get_count(SC_WARNING) == 0); + + REQUIRE(state.resp_cnt == 4 * state.NumberOfIterations); + { + auto& e = state.write_tx; + auto const& send_tx = e.first; + auto const& recv_tx = e.second; + REQUIRE(send_tx.size() == recv_tx.size()); + for(auto i = 0; i < send_tx.size(); ++i) { + REQUIRE(send_tx[i]->get_response_status() == tlm::TLM_OK_RESPONSE); + CHECK(is_equal(*send_tx[i], *recv_tx[i])); + } + } + { + auto& e = state.read_tx; + auto const& send_tx = e.first; + auto const& recv_tx = e.second; + REQUIRE(send_tx.size() == recv_tx.size()); + for(auto i = 0; i < send_tx.size(); ++i) { + REQUIRE(send_tx[i]->get_response_status() == tlm::TLM_OK_RESPONSE); + CHECK(is_equal(*send_tx[i], *recv_tx[i])); + } + } +} diff --git a/tests/apb_pin_level/testbench.h b/tests/apb_pin_level/testbench.h new file mode 100644 index 0000000..bb14d26 --- /dev/null +++ b/tests/apb_pin_level/testbench.h @@ -0,0 +1,89 @@ +#ifndef _TESTBENCH_H_ +#define _TESTBENCH_H_ + +#include +#include +#include + +using namespace sc_core; + +class testbench : public sc_core::sc_module { +public: + enum { DATA_WIDTH = 32, ADDR_WIDTH = 32 }; + using addr_t = typename apb::pin::initiator::addr_t; + using data_t = apb::pin::initiator::data_t; + using strb_t = sc_dt::sc_uint; + sc_core::sc_time clk_period{10, sc_core::SC_NS}; + sc_core::sc_clock clk{"clk", clk_period, 0.5, sc_core::SC_ZERO_TIME, true}; + sc_core::sc_signal rst_n{"rst_n"}; + // initiator side + tlm::scc::initiator_mixin> isck{"isck"}; + apb::pin::initiator intor_bfm{"intor_bfm"}; + // signal accurate bus + sc_core::sc_signal PADDR{"PADDR"}; + sc_core::sc_signal> PPROT{"PPROT"}; + sc_core::sc_signal PNSE{"PNSE"}; + sc_core::sc_signal PSELx{"PSELx"}; + sc_core::sc_signal PENABLE{"PENABLE"}; + sc_core::sc_signal PWRITE{"PWRITE"}; + sc_core::sc_signal PWDATA{"PWDATA"}; + sc_core::sc_signal PSTRB{"PSTRB"}; + sc_core::sc_signal PREADY{"PREADY"}; + sc_core::sc_signal PRDATA{"PRDATA"}; + sc_core::sc_signal PSLVERR{"PSLVERR"}; + sc_core::sc_signal PWAKEUP{"PWAKEUP"}; + // target side + apb::pin::target tgt_bfm{"tgt_bfm"}; + tlm::scc::target_mixin> tsck{"tsck"}; + +public: + SC_HAS_PROCESS(testbench); + testbench() + : testbench("testbench") {} + testbench(sc_core::sc_module_name nm) + : sc_core::sc_module(nm) { + intor_bfm.PCLK_i(clk); + tgt_bfm.PCLK_i(clk); + // bfm to signals + isck(intor_bfm.tsckt); + intor_bfm.PRESETn_i(rst_n); + intor_bfm.PADDR_o(PADDR); + intor_bfm.PPROT_o(PPROT); + intor_bfm.PNSE_o(PNSE); + intor_bfm.PSELx_o(PSELx); + intor_bfm.PENABLE_o(PENABLE); + intor_bfm.PWRITE_o(PWRITE); + intor_bfm.PWDATA_o(PWDATA); + intor_bfm.PSTRB_o(PSTRB); + intor_bfm.PREADY_i(PREADY); + intor_bfm.PRDATA_i(PRDATA); + intor_bfm.PSLVERR_i(PSLVERR); + intor_bfm.PWAKEUP_o(PWAKEUP); + + tgt_bfm.PRESETn_i(rst_n); + tgt_bfm.PADDR_i(PADDR); + tgt_bfm.PPROT_i(PPROT); + tgt_bfm.PNSE_i(PNSE); + tgt_bfm.PSELx_i(PSELx); + tgt_bfm.PENABLE_i(PENABLE); + tgt_bfm.PWRITE_i(PWRITE); + tgt_bfm.PWDATA_i(PWDATA); + tgt_bfm.PSTRB_i(PSTRB); + tgt_bfm.PREADY_o(PREADY); + tgt_bfm.PRDATA_o(PRDATA); + tgt_bfm.PSLVERR_o(PSLVERR); + tgt_bfm.PWAKEUP_i(PWAKEUP); + + tgt_bfm.isckt(tsck); + tsck.register_b_transport([this](tlm::tlm_base_protocol_types::tlm_payload_type& trans, sc_core::sc_time& d) { + if(cb_delegate) + cb_delegate(trans, d); + }); + } + + void run1() {} + void register_b_transport(std::function cb) { cb_delegate = cb; } + std::function cb_delegate; +}; + +#endif // _TESTBENCH_H_ diff --git a/tests/axi4_pin_level/CMakeLists.txt b/tests/axi4_pin_level/CMakeLists.txt index ffcfa7b..53ff21a 100644 --- a/tests/axi4_pin_level/CMakeLists.txt +++ b/tests/axi4_pin_level/CMakeLists.txt @@ -1,7 +1,7 @@ project (axi4_pin_level) add_executable(${PROJECT_NAME} - narrow_burst_test.cpp + burst_test.cpp ${test_util_SOURCE_DIR}/sc_main.cpp ) target_link_libraries (${PROJECT_NAME} PUBLIC test_util) diff --git a/tests/axi4_pin_level/narrow_burst_test.cpp b/tests/axi4_pin_level/burst_test.cpp similarity index 56% rename from tests/axi4_pin_level/narrow_burst_test.cpp rename to tests/axi4_pin_level/burst_test.cpp index 3119369..2315ec8 100644 --- a/tests/axi4_pin_level/narrow_burst_test.cpp +++ b/tests/axi4_pin_level/burst_test.cpp @@ -7,9 +7,59 @@ #include using namespace sc_core; +using tlm_gp_shared_ptr_vec = std::vector; factory::add tb; +//// DataTransfer() +//// ============== +// void DataTransfer(uint64_t Start_Address, unsigned axsize, unsigned axlen, unsigned Data_Bus_Bytes, axi::burst_e Mode, bool IsWrite) { +// auto Number_Bytes = 2u<= Upper_Wrap_Boundary) addr = Lower_Wrap_Boundary; +// } +// } else { +// addr = Aligned_Address + Number_Bytes; +// aligned = true; // All transfers after the first are aligned +// } +// } +// } +// return; +// } bool is_equal(tlm::tlm_generic_payload const& a, tlm::tlm_generic_payload const& b) { auto ret = true; ret &= a.get_command() == b.get_command(); @@ -38,7 +88,9 @@ tlm::tlm_generic_payload* prepare_trans(uint64_t start_address, unsigned addr_in ext->set_size(scc::ilog2(width)); sc_assert(len < (bus_cfg::BUSWIDTH / 8) || len % (bus_cfg::BUSWIDTH / 8) == 0); auto length = (len * 8 - 1) / (8 * width); - if(width == (bus_cfg::BUSWIDTH / 8) && start_address % (bus_cfg::BUSWIDTH / 8)) + // if(width == (bus_cfg::BUSWIDTH / 8) && start_address % (bus_cfg::BUSWIDTH / 8)) + // length++; + if(start_address % (bus_cfg::BUSWIDTH / 8) + width > (bus_cfg::BUSWIDTH / 8)) length++; ext->set_length(length); // ext->set_burst(len * 8 > bus_cfg::buswidth ? axi::burst_e::INCR : axi::burst_e::FIXED); @@ -81,51 +133,55 @@ template unsigned run_scenario(STATE& state) { unsigned int StartAddr{0x0}; for(int i = 0; i < state.NumberOfIterations; ++i) { tlm::scc::tlm_gp_shared_ptr trans = - prepare_trans(StartAddr, 4, state.BurstLengthByte, state.BurstSizeBytes, 1); + prepare_trans(StartAddr + (state.unaligned ? 2 : 0), 4, state.BurstLengthByte, state.BurstSizeBytes, 1); trans->set_command(tlm::TLM_READ_COMMAND); - SCCDEBUG(__FUNCTION__) << "run1, iteration " << i << " TX: " << *trans; + SCCDEBUG("run1") << "iteration " << i << " TX: " << *trans; dut.intor_pe.transport(*trans, false); state.read_tx[axi::get_axi_id(*trans)].first.emplace_back(trans); StartAddr += state.BurstSizeBytes; } + SCCDEBUG("run1") << "finished " << state.NumberOfIterations << " iterations"; }); auto run2 = sc_spawn([&dut, &state]() { unsigned int StartAddr{0x2000}; for(int i = 0; i < state.NumberOfIterations; ++i) { tlm::scc::tlm_gp_shared_ptr trans = - prepare_trans(StartAddr, 4, state.BurstLengthByte, state.BurstSizeBytes, 2); + prepare_trans(StartAddr + (state.unaligned ? 2 : 0), 4, state.BurstLengthByte, state.BurstSizeBytes, 2); trans->set_command(tlm::TLM_WRITE_COMMAND); randomize(*trans); - SCCDEBUG(__FUNCTION__) << "run2, iteration " << i << " TX: " << *trans; + SCCDEBUG("run2") << "iteration " << i << " TX: " << *trans; dut.intor_pe.transport(*trans, false); state.write_tx[axi::get_axi_id(*trans)].first.emplace_back(trans); StartAddr += state.BurstSizeBytes; } + SCCDEBUG("run2") << "finished " << state.NumberOfIterations << " iterations"; }); auto run3 = sc_spawn([&dut, &state]() { unsigned int StartAddr{0x1000}; for(int i = 0; i < state.NumberOfIterations; ++i) { tlm::scc::tlm_gp_shared_ptr trans = - prepare_trans(StartAddr, 4, state.BurstLengthByte, state.BurstSizeBytes, 3); + prepare_trans(StartAddr + (state.unaligned ? 2 : 0), 4, state.BurstLengthByte, state.BurstSizeBytes, 3); trans->set_command(tlm::TLM_READ_COMMAND); - SCCDEBUG(__FUNCTION__) << "run3, iteration " << i << " TX: " << *trans; + SCCDEBUG("run3") << "iteration " << i << " TX: " << *trans; dut.intor_pe.transport(*trans, false); state.read_tx[axi::get_axi_id(*trans)].first.emplace_back(trans); StartAddr += state.BurstSizeBytes; } + SCCDEBUG("run3") << "finished " << state.NumberOfIterations << " iterations"; }); auto run4 = sc_spawn([&dut, &state]() { unsigned int StartAddr{0x3000}; for(int i = 0; i < state.NumberOfIterations; ++i) { tlm::scc::tlm_gp_shared_ptr trans = - prepare_trans(StartAddr, 4, state.BurstLengthByte, state.BurstSizeBytes, 4); + prepare_trans(StartAddr + (state.unaligned ? 2 : 0), 4, state.BurstLengthByte, state.BurstSizeBytes, 4); trans->set_command(tlm::TLM_WRITE_COMMAND); randomize(*trans); - SCCDEBUG(__FUNCTION__) << "run4, iteration " << i << " TX: " << *trans; + SCCDEBUG("run4") << "iteration " << i << " TX: " << *trans; dut.intor_pe.transport(*trans, false); state.write_tx[axi::get_axi_id(*trans)].first.emplace_back(trans); StartAddr += state.BurstSizeBytes; } + SCCDEBUG("run4") << "finished " << state.NumberOfIterations << " iterations"; }); unsigned cycles{0}; @@ -136,21 +192,23 @@ template unsigned run_scenario(STATE& state) { return cycles; } -void axi4_burst_alignment(bool pipelined_wrreq, bool write_bp) { +void axi4_burst_alignment(bool pipelined_wrreq, bool write_bp, bool unaligned = false) { + SCCINFO(__FUNCTION__) << "starting with pipelined_wrreq=" << pipelined_wrreq << " and write_bp=" << write_bp; struct { unsigned int ResetCycles{4}; unsigned int BurstLengthByte{16}; unsigned int BurstSizeBytes{8}; unsigned int NumberOfIterations{8}; - std::unordered_map, std::vector>> read_tx; - std::unordered_map, std::vector>> - write_tx; + std::unordered_map> read_tx; + std::unordered_map> write_tx; unsigned resp_cnt{0}; + bool unaligned{false}; } state; + state.unaligned = unaligned; auto& dut = factory::get(); dut.intor_bfm.pipelined_wrreq = pipelined_wrreq; - dut.tgt_pe.wr_data_accept_delay.value = write_bp ? 1 : 0; + dut.tgt_pe.wr_data_accept_delay.set_value(write_bp ? 1 : 0); auto cycles = run_scenario(state); REQUIRE(cycles < 1000); @@ -172,27 +230,39 @@ void axi4_burst_alignment(bool pipelined_wrreq, bool write_bp) { auto const& recv_tx = e.second.second; REQUIRE(send_tx.size() == recv_tx.size()); for(auto i = 0; i < send_tx.size(); ++i) { + auto addr = send_tx[i]->get_address(); + if(addr % (testbench::bus_cfg::ADDRWIDTH / 8)) { + CHECK(send_tx[i]->get_data_length() <= recv_tx[i]->get_data_length()); + CHECK(send_tx[i]->get_byte_enable_length() <= recv_tx[i]->get_byte_enable_length()); + // adjust the length of the read due to misalignment + recv_tx[i]->set_data_length(send_tx[i]->get_data_length()); + recv_tx[i]->set_byte_enable_length(send_tx[i]->get_byte_enable_length()); + recv_tx[i]->set_streaming_width(send_tx[i]->get_streaming_width()); + } REQUIRE(send_tx[i]->get_response_status() == tlm::TLM_OK_RESPONSE); CHECK(is_equal(*send_tx[i], *recv_tx[i])); } } } -void axi4_narrow_burst(bool pipelined_wrreq, bool write_bp) { +void axi4_narrow_burst(bool pipelined_wrreq, bool write_bp, bool unaligned = false) { + SCCINFO(__FUNCTION__) << "starting with pipelined_wrreq=" << pipelined_wrreq << ", write_bp = " << write_bp + << " and unaligned=" << unaligned; struct { unsigned int ResetCycles{4}; unsigned int BurstLengthByte{16}; unsigned int BurstSizeBytes{4}; unsigned int NumberOfIterations{8}; - std::unordered_map, std::vector>> read_tx; - std::unordered_map, std::vector>> - write_tx; + std::unordered_map> read_tx; + std::unordered_map> write_tx; unsigned resp_cnt{0}; + bool unaligned{false}; } state; + state.unaligned = unaligned; auto& dut = factory::get(); dut.intor_bfm.pipelined_wrreq = pipelined_wrreq; - dut.tgt_pe.wr_data_accept_delay.value = write_bp ? 1 : 0; + dut.tgt_pe.wr_data_accept_delay.set_value(write_bp ? 1 : 0); auto cycles = run_scenario(state); REQUIRE(cycles < 1000); @@ -218,16 +288,32 @@ void axi4_narrow_burst(bool pipelined_wrreq, bool write_bp) { TEST_CASE("axi4_burst_alignment", "[AXI][pin-level]") { axi4_burst_alignment(false, false); } +TEST_CASE("axi4_burst_alignment_unaligned_addr", "[AXI][pin-level]") { axi4_burst_alignment(false, false, true); } + TEST_CASE("axi4_narrow_burst", "[AXI][pin-level]") { axi4_narrow_burst(false, false); } +// TEST_CASE("axi4_narrow_burst_unaligned_addr", "[AXI][pin-level]") { axi4_narrow_burst(false, false, true); } + TEST_CASE("axi4_burst_alignment_with_bp", "[AXI][pin-level]") { axi4_burst_alignment(false, true); } +TEST_CASE("axi4_burst_alignment_with_bp_unaligned_addr", "[AXI][pin-level]") { axi4_burst_alignment(false, true, true); } + TEST_CASE("axi4_narrow_burst_with_bp", "[AXI][pin-level]") { axi4_narrow_burst(false, true); } +// TEST_CASE("axi4_narrow_burst_with_bp_unaligned_addr", "[AXI][pin-level]") { axi4_narrow_burst(false, true, true); } + TEST_CASE("axi4_burst_alignment_pipelined_write", "[AXI][pin-level]") { axi4_burst_alignment(true, false); } +TEST_CASE("axi4_burst_alignment_pipelined_write_unaligned_addr", "[AXI][pin-level]") { axi4_burst_alignment(true, false, true); } + TEST_CASE("axi4_narrow_burst_pipelined_write", "[AXI][pin-level]") { axi4_narrow_burst(true, false); } +// TEST_CASE("axi4_narrow_burst_pipelined_write_unaligned_addr", "[AXI][pin-level]") { axi4_narrow_burst(true, false, true); } + TEST_CASE("axi4_burst_alignment_pipelined_write_with_bp", "[AXI][pin-level]") { axi4_burst_alignment(true, true); } +TEST_CASE("axi4_burst_alignment_pipelined_write_with_bp_unaligned_addr", "[AXI][pin-level]") { axi4_burst_alignment(true, true, true); } + TEST_CASE("axi4_narrow_burst_pipelined_write_with_bp", "[AXI][pin-level]") { axi4_narrow_burst(true, true); } + +// TEST_CASE("axi4_narrow_burst_pipelined_write_with_bp_unaligned_addr", "[AXI][pin-level]") { axi4_narrow_burst(true, true, true); } diff --git a/tests/axi4_pin_level/waves.gtkw b/tests/axi4_pin_level/waves.gtkw new file mode 100644 index 0000000..222c184 --- /dev/null +++ b/tests/axi4_pin_level/waves.gtkw @@ -0,0 +1,116 @@ +[*] +[*] GTKWave Analyzer v3.3.118 (w)1999-2023 BSI +[*] Wed Jan 8 16:33:12 2025 +[*] +[dumpfile] "/scratch/eyck/workarea/MINRES/SystemC-Components-Test/axi4_pin_level.fst" +[dumpfile_mtime] "Wed Jan 8 16:32:32 2025" +[dumpfile_size] 7261 +[savefile] "/scratch/eyck/workarea/MINRES/SystemC-Components-Test/tests/axi4_pin_level/waves.gtkw" +[timestart] 0 +[size] 2560 1288 +[pos] -1 -1 +*-20.062529 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 +[treeopen] testbench. +[sst_width] 304 +[signals_width] 243 +[sst_expanded] 1 +[sst_vpaned_height] 396 +@28 +testbench.clk +testbench.rst +@800200 +-ar +@28 +testbench.ar_valid +testbench.ar_ready +@22 +testbench.ar_addr[31:0] +@28 +testbench.ar_burst[1:0] +@22 +testbench.ar_cache[3:0] +testbench.ar_id[3:0] +testbench.ar_len[7:0] +@28 +testbench.ar_lock +testbench.ar_prot[2:0] +@22 +testbench.ar_qos[3:0] +testbench.ar_region[3:0] +@28 +testbench.ar_size[2:0] +testbench.ar_user +@1000200 +-ar +@800200 +-r +@28 +testbench.r_valid +testbench.r_ready +testbench.r_last +@22 +testbench.r_data[63:0] +testbench.r_id[3:0] +@28 +testbench.r_resp[1:0] +testbench.r_trace +testbench.r_user +@1000200 +-r +@800200 +-aw +@28 +testbench.aw_valid +testbench.aw_ready +@22 +testbench.aw_id[3:0] +testbench.aw_addr[31:0] +@28 +testbench.aw_burst[1:0] +@22 +testbench.aw_cache[3:0] +testbench.aw_len[7:0] +@28 +testbench.aw_lock +testbench.aw_prot[2:0] +@22 +testbench.aw_qos[3:0] +testbench.aw_region[3:0] +@28 +testbench.aw_size[2:0] +testbench.aw_user +@1000200 +-aw +@800200 +-w +@29 +testbench.w_valid +testbench.w_ready +testbench.w_ack +@23 +testbench.w_data[63:0] +testbench.w_id[3:0] +@29 +testbench.w_last +@23 +testbench.w_strb[7:0] +@29 +testbench.w_trace +testbench.w_user +@1000200 +-w +@800200 +-b +@28 +testbench.b_valid +testbench.b_ready +@22 +testbench.b_id[3:0] +@28 +testbench.b_resp[1:0] +testbench.b_trace +testbench.b_user +@1000200 +-b +[pattern_trace] 1 +[pattern_trace] 0 diff --git a/tests/cci_param_restricted/test.cpp b/tests/cci_param_restricted/test.cpp index 925edbc..63d6d63 100644 --- a/tests/cci_param_restricted/test.cpp +++ b/tests/cci_param_restricted/test.cpp @@ -2,12 +2,12 @@ #define SC_INCLUDE_DYNAMIC_PROCESSES #include #endif +#include #include #include #include #include #include - using namespace sc_core; struct top : public sc_core::sc_module { diff --git a/tests/configuration/sc_main.cpp b/tests/configuration/sc_main.cpp index f4886a0..d00620a 100644 --- a/tests/configuration/sc_main.cpp +++ b/tests/configuration/sc_main.cpp @@ -33,7 +33,6 @@ #include "top_module.h" #include -#include #include /** diff --git a/tests/cxs_tlm/CMakeLists.txt b/tests/cxs_tlm/CMakeLists.txt new file mode 100644 index 0000000..ede8eff --- /dev/null +++ b/tests/cxs_tlm/CMakeLists.txt @@ -0,0 +1,8 @@ +project (cxs_tlm) +add_executable(${PROJECT_NAME} + csx_packet_test.cpp + ${test_util_SOURCE_DIR}/sc_main.cpp +) +target_link_libraries (${PROJECT_NAME} PUBLIC scc::busses test_util) + +catch_discover_tests(${PROJECT_NAME}) diff --git a/tests/cxs_tlm/csx_packet_test.cpp b/tests/cxs_tlm/csx_packet_test.cpp new file mode 100644 index 0000000..8bfdcf3 --- /dev/null +++ b/tests/cxs_tlm/csx_packet_test.cpp @@ -0,0 +1,171 @@ + +#include "testbench.h" +#include +#include +#undef CHECK +#include +#include +#include + +using namespace sc_core; +namespace cxs { +factory::add> tb8; +factory::add> tb9; +factory::add> tb10; + +template unsigned run_scenario(STATE& state, unsigned burst_factor = 0) { + auto& dut = factory::get>(); + if(burst_factor) + dut.tx.burst_len.set_value(burst_factor); + dut.rst.write(true); + sc_start(state.reset_cycles * dut.clk.period()); + dut.rst.write(false); + sc_start(dut.clk.period()); + + auto run1 = sc_spawn([&dut, &state]() { + auto burst_cnt{0}; + std::deque expected_pkt; + for(auto size : state.packet_sizes) { + cxs_pkt_shared_ptr tx_pkt = cxs_pkt_mm::get().allocate(); + tx_pkt->get_data().resize(size); + SCCDEBUG("run_scenario") << "Transmitting packet with size " << size; + auto phase{tlm::nw::REQUEST}; + sc_core::sc_time t = sc_core::SC_ZERO_TIME; + auto status = dut.isck->nb_transport_fw(*tx_pkt, phase, t); + expected_pkt.emplace_back(tx_pkt); + tx_pkt = nullptr; + REQUIRE(status == tlm::TLM_UPDATED); + REQUIRE(phase == tlm::nw::CONFIRM); + if(++burst_cnt == state.granularity) { + auto rec_cnt = 0u; + while(rec_cnt < burst_cnt) { + ::sc_core::wait(dut.recv.data_written_event()); + while(!dut.recv.empty()) { + auto recv_pkt = dut.recv.front(); + dut.recv.pop_front(); + tx_pkt = expected_pkt.front(); + expected_pkt.pop_front(); + REQUIRE(tx_pkt == recv_pkt); + REQUIRE(recv_pkt->get_data().size() == state.packet_sizes[state.resp_cnt]); + state.resp_cnt++; + rec_cnt++; + SCCDEBUG("run_scenario") << "Received packet with size " << recv_pkt->get_data().size() + << ", total number of packets is " << state.resp_cnt; + } + } + burst_cnt = 0; + } + } + }); + + unsigned cycles{0}; + while(cycles < state.max_cycles && !(run1.terminated())) { + // while(cycles<1000 && !(run5.terminated())){ + sc_start(10 * dut.clk.period()); + cycles += 10; + } + return cycles; +} + +template unsigned run_scenario(int width, STATE& state, unsigned burst_factor = 0) { + switch(width) { + case 8: + case 256: + return run_scenario<256>(state); + case 9: + case 512: + return run_scenario<512>(state); + case 10: + case 1024: + return run_scenario<1024>(state); + } + return 0; +} + +TEST_CASE("single-packet", "[CXS][tlm-level]") { + struct { + unsigned int reset_cycles{4}; + unsigned int max_cycles = 5000; + std::vector packet_sizes; + unsigned granularity{1}; + unsigned resp_cnt{0}; + } state; + + state.packet_sizes.assign({4, 8, 16, 32, 64, 128, 256, 1024}); + for(auto width = 8; width < 11; ++width) { + state.resp_cnt = 0; + auto cycles = run_scenario(width, state); + + REQUIRE(cycles < state.max_cycles); + REQUIRE(sc_report_handler::get_count(SC_ERROR) == 0); + REQUIRE(sc_report_handler::get_count(SC_WARNING) == 0); + + REQUIRE(state.resp_cnt == state.packet_sizes.size()); + } +} + +TEST_CASE("multi-packet", "[CXS][tlm-level]") { + struct { + unsigned int reset_cycles{4}; + unsigned int max_cycles = 5000; + std::vector packet_sizes; + unsigned granularity{2}; + unsigned resp_cnt{0}; + } state; + + state.packet_sizes.assign({4, 8, 16, 32, 16, 64, 16, 128, 16, 256, 16, 1024}); + for(auto width = 8; width < 11; ++width) { + state.resp_cnt = 0; + auto cycles = run_scenario(width, state); + + REQUIRE(cycles < state.max_cycles); + REQUIRE(sc_report_handler::get_count(SC_ERROR) == 0); + REQUIRE(sc_report_handler::get_count(SC_WARNING) == 0); + + REQUIRE(state.resp_cnt == state.packet_sizes.size()); + } +} +TEST_CASE("single-packet-burst2", "[CXS][tlm-level]") { + struct { + unsigned int reset_cycles{4}; + unsigned int max_cycles = 5000; + std::vector packet_sizes; + unsigned granularity{1}; + unsigned resp_cnt{0}; + } state; + + state.packet_sizes.assign({4, 8, 16, 32, 64, 128, 256, 1024}); + for(auto width = 8; width < 11; ++width) { + state.resp_cnt = 0; + auto cycles = run_scenario(width, state, 2); + + REQUIRE(cycles < state.max_cycles); + REQUIRE(sc_report_handler::get_count(SC_ERROR) == 0); + REQUIRE(sc_report_handler::get_count(SC_WARNING) == 0); + + REQUIRE(state.resp_cnt == state.packet_sizes.size()); + } +} + +TEST_CASE("multi-packet-burst2", "[CXS][tlm-level]") { + struct { + unsigned int reset_cycles{4}; + unsigned int max_cycles = 5000; + std::vector packet_sizes; + unsigned granularity{2}; + unsigned resp_cnt{0}; + } state; + + state.packet_sizes.assign({4, 8, 16, 32, 16, 64, 16, 128, 16, 256, 16, 1024}); + for(auto width = 8; width < 11; ++width) { + state.resp_cnt = 0; + auto cycles = run_scenario(width, state, 2); + + REQUIRE(cycles < state.max_cycles); + REQUIRE(sc_report_handler::get_count(SC_ERROR) == 0); + REQUIRE(sc_report_handler::get_count(SC_WARNING) == 0); + + REQUIRE(state.resp_cnt == state.packet_sizes.size()); + } +} +} // namespace cxs diff --git a/tests/cxs_tlm/testbench.h b/tests/cxs_tlm/testbench.h new file mode 100644 index 0000000..00d99b9 --- /dev/null +++ b/tests/cxs_tlm/testbench.h @@ -0,0 +1,77 @@ +#ifndef _TESTBENCH_H_ +#define _TESTBENCH_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace sc_core; +using namespace sc_dt; +using namespace std; +namespace cxs { + +const char* sc_gen_unique_name(const char*, bool preserve_first); +template struct testbench : public sc_core::sc_module { + + using transaction_type = cxs_packet_types::tlm_payload_type; + using phase_type = cxs_packet_types::tlm_phase_type; + + sc_core::sc_clock clk{"clk", 1_ns}; + sc_core::sc_signal rst{"rst"}; + tlm::nw::initiator_mixin, cxs_packet_types> isck{"isck"}; + cxs_transmitter tx{"tx"}; + cxs_channel cxs_chan{"cxs_chan"}; + cxs_receiver rx{"rx"}; + tlm::nw::target_mixin, cxs_packet_types> tsck{"tsck"}; + + testbench() + : testbench(sc_core::sc_gen_unique_name("testbench", false)) {} + + testbench(sc_core::sc_module_name const& nm) + : sc_module(nm) { + isck.register_nb_transport_bw( + [this](transaction_type& trans, phase_type& phase, sc_core::sc_time& t) { return this->nb_transport_fw(trans, phase, t); }); + tsck.register_nb_transport_fw( + [this](transaction_type& trans, phase_type& phase, sc_core::sc_time& t) { return this->nb_transport_fw(trans, phase, t); }); + isck(tx.tsck); + tx.clk_i(clk); + tx.rst_i(rst); + tx.isck(cxs_chan.tsck); + cxs_chan.isck(rx.tsck); + rx.clk_i(clk); + rx.rst_i(rst); + rx.isck(tsck); + cxs_chan.channel_delay.set_value(100_ns); + rx.max_credit.set_value(15); + } + + tlm::tlm_sync_enum nb_transport_fw(transaction_type& trans, phase_type& phase, sc_core::sc_time& t) { + if(phase == tlm::nw::REQUEST) { + SCCINFO(SCMOD) << "Received non-blocking transaction with phase " << phase.get_name(); + recv.push_back(&trans); + phase = tlm::nw::CONFIRM; + return tlm::TLM_UPDATED; + } + throw std::runtime_error("illegal request in forward path"); + } + + tlm::tlm_sync_enum nb_transport_bw(transaction_type& trans, phase_type& phase, sc_core::sc_time& t) { + if(phase == tlm::nw::CONFIRM) { + confirmation_evt.notify(sc_core::SC_ZERO_TIME); + return tlm::TLM_ACCEPTED; + } + throw std::runtime_error("illegal response in backward path"); + } + + sc_core::sc_event confirmation_evt; + scc::fifo_w_cb recv; +}; +} // namespace cxs +#endif // _TESTBENCH_H_ diff --git a/tests/sc_fixed_tracing/CMakeLists.txt b/tests/sc_fixed_tracing/CMakeLists.txt new file mode 100644 index 0000000..8dcb049 --- /dev/null +++ b/tests/sc_fixed_tracing/CMakeLists.txt @@ -0,0 +1,3 @@ +add_executable (sc_fixed_tracing sc_main.cpp) +target_link_libraries (sc_fixed_tracing LINK_PUBLIC scc-sysc) +add_test(NAME sc_fixed_tracing_test COMMAND sc_fixed_tracing ) \ No newline at end of file diff --git a/tests/sc_fixed_tracing/sc_main.cpp b/tests/sc_fixed_tracing/sc_main.cpp new file mode 100644 index 0000000..769b18f --- /dev/null +++ b/tests/sc_fixed_tracing/sc_main.cpp @@ -0,0 +1,82 @@ +#define SC_INCLUDE_FX +#include +#include +#include +#include +#include +#include +#include + +using namespace sc_dt; +using namespace std; + +struct testbench : public sc_core::sc_module { + scc::sc_variable> a{"a", sc_dt::sc_fixed<6, 4>()}; + scc::sc_variable> b_sc_sat{"b_sc_sat", 0}; + scc::sc_variable> a_qant{"a_qant", 0}; + scc::sc_variable> b_sc_rnd{"b_sc_rnd", 0}; + scc::sc_variable> b_sc_trn{"b_sc_trn", 0}; + sc_fixed<5, 3> a_fixed; + sc_dt::sc_fix a_fix{5, 3}; + sc_fxtype_params params{5, 4}; + sc_fxtype_context context{params}; + // becase we do not specify in b_fix constructor anything + // the parameters are taken form the latest created context + sc_fix b_fix; + sc_fix c_fix{5, 3}; + + testbench(sc_core::sc_module_name const& nm) + : sc_module(nm) { + SC_HAS_PROCESS(testbench); + SC_THREAD(run); + } + + void trace(sc_core::sc_trace_file* trf) const override { + a.trace(trf); + scc::sc_trace(trf, a_fixed, std::string(name()) + ".a_fixed"); + scc::sc_trace(trf, a_fix, std::string(name()) + ".a_fix"); + scc::sc_trace(trf, b_fix, std::string(name()) + ".b_fix"); + scc::sc_trace(trf, c_fix, std::string(name()) + ".c_fix"); + } + + void run() { + wait(1_ns); + init(); + wait(1_ns); + test_overflow_modes(); + wait(1_ns); + test_quantization_modes(); + wait(1_ns); + this->a = 2; + wait(1_ps); + sc_core::sc_stop(); + } + + void init() { + a_fixed = 1.75; + a_fix = 1.75; + b_fix = 1.75; + c_fix = 1.75; + } + void test_overflow_modes() { + a = -7; + b_sc_sat = *a; + } + + void test_quantization_modes() { + a_qant = -2.3125; + b_sc_rnd = *a_qant; + b_sc_trn = *a_qant; + } +}; + +int sc_main(int sc_argc, char* sc_argv[]) { + scc::init_logging(scc::log::INFO); + scc::configurer cfg(""); + scc::tracer trc("sc_fixed_tracing"); + testbench tb("tb"); + sc_core::sc_start(); + SCCINFO("sc_main") << "End Simulation."; + + return sc_core::sc_report_handler::get_count(sc_core::SC_ERROR) + sc_core::sc_report_handler::get_count(sc_core::SC_WARNING); +} // End of 'sc_main'