Skip to content

Commit 799b9af

Browse files
committed
Add memory boundary test
- Added unit tests to CI workflow. - Added Dockerfile for testing environment setup. - Created `TESTING.md` for guidelines on running tests. - Implemented memory boundary test in `tests/memory_boundary_test.cpp` with CMake configuration.
1 parent 7be5ff5 commit 799b9af

File tree

7 files changed

+224
-44
lines changed

7 files changed

+224
-44
lines changed

.github/workflows/ci-transaction_recording.yml

Lines changed: 0 additions & 44 deletions
This file was deleted.

.github/workflows/ci.yml

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
paths:
6+
- '**.cpp'
7+
- '**.h'
8+
- '**CMakeLists.txt'
9+
- 'tests/**'
10+
- '.github/workflows/**'
11+
pull_request:
12+
paths:
13+
- '**.cpp'
14+
- '**.h'
15+
- '**CMakeLists.txt'
16+
- 'tests/**'
17+
- '.github/workflows/**'
18+
19+
jobs:
20+
unit-tests:
21+
name: unit-tests (C++20)
22+
runs-on: ubuntu-latest
23+
steps:
24+
- uses: actions/checkout@v4
25+
26+
- name: Cache Conan
27+
uses: actions/cache@v4
28+
with:
29+
path: ~/.conan
30+
key: conan-${{ runner.os }}-unit-cpp20-${{ hashFiles('conanfile.txt') }}
31+
32+
- name: Update submodules
33+
run: git submodule update --init --recursive
34+
35+
- name: Install dependencies
36+
run: |
37+
sudo apt-get update
38+
sudo apt-get install -y cmake g++ python3-pip
39+
pip3 install "conan<2.0"
40+
41+
- name: Configure
42+
run: >
43+
cmake -S . -B build
44+
-DBUILD_TESTING=ON
45+
-DCMAKE_CXX_STANDARD=20
46+
47+
- name: Build
48+
run: cmake --build build -j
49+
50+
- name: Run unit tests
51+
run: ctest --output-on-failure
52+
working-directory: build
53+
54+
txrec:
55+
name: txrec (C++${{ matrix.cpp_std }})
56+
runs-on: ubuntu-latest
57+
strategy:
58+
matrix:
59+
cpp_std: [11, 14, 17, 20]
60+
steps:
61+
- uses: actions/checkout@v4
62+
63+
- name: Cache Conan
64+
uses: actions/cache@v4
65+
with:
66+
path: ~/.conan
67+
key: conan-${{ runner.os }}-txrec-cpp${{ matrix.cpp_std }}-${{ hashFiles('conanfile.txt') }}
68+
69+
- name: Update submodules
70+
run: git submodule update --init --recursive
71+
72+
- name: Install dependencies
73+
run: |
74+
sudo apt-get update
75+
sudo apt-get install -y cmake g++ python3-pip
76+
pip3 install "conan<2.0"
77+
78+
- name: Configure
79+
run: >
80+
cmake -S . -B build
81+
-DBUILD_TESTING=OFF
82+
-DCMAKE_CXX_STANDARD=${{ matrix.cpp_std }}
83+
84+
- name: Build
85+
run: cmake --build build -j
86+
87+
- name: Run transaction_recording example
88+
run: ./build/examples/transaction_recording/transaction_recording

CMakeLists.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ project(scc VERSION 2025.09 LANGUAGES CXX C)
77
option(USE_CWR_SYSTEMC "Use Synopsys Virtualizer SystemC" OFF)
88
option(USE_NCSC_SYSTEMC "Cadence Xcelium SystemC" OFF)
99
option(ENABLE_CONAN "Enable the use of conan in standalone build" ON)
10+
option(BUILD_TESTING "Enable building tests" OFF)
1011
option(BUILD_SCC_DOCUMENTATION "Create and install the HTML based API documentation (requires Doxygen)" OFF)
1112
option(FULL_TRACE_TYPE_LIST "Test for extended set of templated datatypes" OFF)
1213
#Note: this needs to match the SystemC kernel build options
@@ -44,6 +45,9 @@ if(CMAKE_PROJECT_NAME STREQUAL "scc")
4445
# Boost on CentOS quirks end
4546
endif()
4647
set(CONAN_PACKAGE_LIST jsoncpp/1.9.5 yaml-cpp/0.6.3 spdlog/1.9.2 fmt/8.0.1 zlib/1.2.12 lz4/1.9.4 boost/1.75.0)
48+
if(BUILD_TESTING)
49+
list(APPEND CONAN_PACKAGE_LIST gtest/1.14.0)
50+
endif()
4751
if(BUILD_SCC_DOCUMENTATION)
4852
list(APPEND CONAN_PACKAGE_LIST doxygen/1.9.2)
4953
endif()
@@ -145,6 +149,10 @@ include(CheckSymbolExists)
145149
# Check for function getenv()
146150
check_symbol_exists(getenv "stdlib.h" HAVE_GETENV)
147151

152+
if(BUILD_TESTING)
153+
include(CTest)
154+
endif()
155+
148156
if(NOT TARGET lz4::lz4)
149157
message(STATUS "${PROJECT_NAME}: using built-in version of lz4")
150158
add_subdirectory(third_party/lz4-1.9.4)
@@ -165,6 +173,10 @@ if(SystemC_FOUND)
165173
endif()
166174
endif()
167175

176+
if(BUILD_TESTING)
177+
add_subdirectory(tests)
178+
endif()
179+
168180
# Define the scc library
169181
add_library(scc INTERFACE)
170182
add_library(scc::scc ALIAS scc)

Dockerfile.test

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
FROM ubuntu:22.04
2+
3+
ENV DEBIAN_FRONTEND=noninteractive
4+
5+
RUN apt-get update && \
6+
apt-get install -y --no-install-recommends \
7+
build-essential \
8+
cmake \
9+
git \
10+
python3 \
11+
python3-pip \
12+
ca-certificates && \
13+
pip3 install "conan<2.0" && \
14+
rm -rf /var/lib/apt/lists/*
15+
16+
WORKDIR /work

TESTING.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Running Tests
2+
3+
This repository has a GoogleTest-based suite (see `tests/`). The tests target the CMake option `BUILD_TESTING=ON` and require the same dependencies as the main build plus GoogleTest (fetched automatically via `FetchContent`).
4+
5+
## Prerequisites
6+
7+
- CMake ≥ 3.20
8+
- A C++ compiler (GCC/Clang) with C++17 or later
9+
- Python 3 with `conan<2.0` installed. A virtual environment is recommended:
10+
11+
```bash
12+
python3 -m venv .venv
13+
source .venv/bin/activate
14+
pip install "conan<2.0"
15+
```
16+
17+
If Conan cannot supply SystemC/CCI on your host, use the Docker flow below or point CMake at a local SystemC install via `SYSTEMC_HOME`.
18+
19+
## Configure and Build
20+
21+
```bash
22+
cmake -S . -B build -DBUILD_TESTING=ON -DCMAKE_CXX_STANDARD=20
23+
cmake --build build -j
24+
```
25+
26+
## Run Tests
27+
28+
```bash
29+
cd build
30+
31+
# unit tests
32+
ctest --output-on-failure
33+
34+
# transaction recording example binary
35+
./examples/transaction_recording/transaction_recording
36+
```
37+
38+
## Run Tests in Docker (Linux toolchain)
39+
40+
If your host setup cannot fetch SystemC via Conan, use the provided Dockerfile:
41+
42+
```bash
43+
# from repo root
44+
docker build -f Dockerfile.test -t scc-tests .
45+
docker run --rm -v "$PWD":/work -w /work scc-tests /bin/bash -lc "\
46+
cmake -S . -B build -DBUILD_TESTING=ON -DCMAKE_CXX_STANDARD=20 && \
47+
cmake --build build -j && \
48+
cd build && ctest --output-on-failure && \
49+
./examples/transaction_recording/transaction_recording"
50+
```
51+
52+
## CI
53+
54+
Tests run in `.github/workflows/ci.yml`, which configures with `-DBUILD_TESTING=ON`, builds, runs `ctest`, and executes the `transaction_recording` example for C++ standards 11/14/17/20.

tests/CMakeLists.txt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
find_package(GTest REQUIRED)
2+
3+
add_executable(memory_boundary_test
4+
memory_boundary_test.cpp
5+
)
6+
7+
target_link_libraries(memory_boundary_test
8+
PRIVATE
9+
GTest::gtest_main
10+
scc::scc
11+
SystemC::systemc
12+
)
13+
target_compile_definitions(memory_boundary_test PRIVATE SC_DISABLE_API_VERSION_CHECK)
14+
15+
add_test(NAME memory_boundary_test COMMAND memory_boundary_test)

tests/memory_boundary_test.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Validates that handle_operation does not overwrite past the requested length
2+
#include <array>
3+
#include <systemc>
4+
#include <tlm>
5+
#include <gtest/gtest.h>
6+
7+
#include "components/scc/memory.h"
8+
#include "scc/cci_broker.h"
9+
10+
TEST(MemoryBoundaryTest, ReadAcrossPageDoesNotOverwriteBuffer) {
11+
static scc::cci_broker global_broker("global_broker");
12+
static auto broker_handle = cci::cci_register_broker(&global_broker);
13+
constexpr uint64_t kPageSize = 1ull << 24; // matches util::sparse_array default page size
14+
scc::memory<(kPageSize + 2u)> mem{"mem"};
15+
16+
std::array<uint8_t, 2> write_data{{0xAAu, 0xBBu}};
17+
tlm::tlm_generic_payload write;
18+
sc_core::sc_time delay = sc_core::SC_ZERO_TIME;
19+
write.set_command(tlm::TLM_WRITE_COMMAND);
20+
write.set_address(kPageSize - 1); // straddles page boundary
21+
write.set_data_length(write_data.size());
22+
write.set_streaming_width(write_data.size());
23+
write.set_data_ptr(write_data.data());
24+
mem.handle_operation(write, delay);
25+
26+
std::array<uint8_t, 4> read_buf{{0xEEu, 0x00u, 0x00u, 0xEEu}};
27+
tlm::tlm_generic_payload read;
28+
read.set_command(tlm::TLM_READ_COMMAND);
29+
read.set_address(kPageSize - 1);
30+
read.set_data_length(write_data.size());
31+
read.set_streaming_width(write_data.size());
32+
read.set_data_ptr(read_buf.data() + 1); // leave guard bytes at both ends
33+
mem.handle_operation(read, delay);
34+
35+
EXPECT_EQ(read_buf[0], 0xEEu); // leading guard untouched
36+
EXPECT_EQ(read_buf[1], 0xAAu); // first byte read correctly
37+
EXPECT_EQ(read_buf[2], 0xBBu); // second byte read correctly
38+
EXPECT_EQ(read_buf[3], 0xEEu); // trailing guard must remain
39+
}

0 commit comments

Comments
 (0)