C++14 signal processing middleware for TI C7x DSPs (AM62DX, AM275x, J722S).
TISP provides a graph-based framework where signal processing nodes (VirtualOp
subclasses) are assembled into an opVec and executed sequentially. Optional
SuperNode wrappers add DMA-driven L2SRAM block processing for throughput-critical
paths.
- Architecture
- Node Library
- Directory Structure
- Dependencies
- Quick Start — West Workspace (recommended)
- Quick Start — Legacy SDK Build
- Build Reference
- Running Tests
- Code Style
- Golden Rules
Every signal processing node derives from TISP::VirtualOp:
class VirtualOp {
public:
virtual const char *getNodeName() const noexcept = 0;
virtual uint32_t getNodeId() const noexcept = 0;
virtual const char *getParams() const noexcept = 0;
virtual void exec() noexcept = 0; // hot path
virtual void setAddr(SetAddr_t &, SetAddrMode_t) noexcept = 0;
};All 63 nodes follow the same template: template <typename T> class Name final : public VirtualOp.
using opVec = std::vector<std::unique_ptr<VirtualOp>>;Build a graph by pushing nodes onto an opVec, then execute it:
auto graph = std::make_unique<TISP::opVec>();
graph->push_back(std::make_unique<TISP::DSPLIB::CascadeBiquad<float>>(pIn, pOut, coeffs, nStages, nCh));
graph->push_back(std::make_unique<TISP::AUDIOLIB::Gain<float>>(pOut, pOut2, gain, nCh));
TISP::execute::graph(graph); // calls exec() on each node with profilerSuperNodes wrap an opVec and execute it on L2SRAM block buffers while DMA
transfers data between DDR and L2SRAM in a ping-pong pipeline. The embedded
opVec nodes have their I/O addresses rebound to L2SRAM via setAddr().
Six variants are provided: I2dToO2d, I2dToO2dDiffDims, I2dI2dToO2d,
I2dI2dToO2dO2d, I2dToO2dTranspose, i2d_to_o2dMatMul.
| Region | Latency | Typical use |
|---|---|---|
| L2SRAM | 0 wait states | DMA buffers, twiddle factors, node objects |
| DDR | ~150 cycles | Bulk input/output frames |
Node objects are placed in L2SRAM via placement new + L2BumpAllocator so the
vtable pointer is zero-wait-state on every exec() call.
| Namespace | Count | Nodes |
|---|---|---|
TISP::AUDIOLIB |
31 | Gain, Delay, Mux, Limiter, ASRC, NLMS, Mixer, Router, … |
TISP::MATHLIB |
15 | Sin, Cos, Tan, Exp, Log, Sqrt, Div, … |
TISP::DSPLIB |
10 | CascadeBiquad, Fir, MatMul, Interleave, AddNCh, … |
TISP::FFTLIB |
3 | FFT1dBatched, RFFT1dBatched, IFFTR1dBatched |
TISP::misc |
4 | BlockCopy, DataConvert, Dummy, zeroOutRFFT |
TISP::SuperNode |
6 | DMA block-processing wrappers |
One header per node under includes/; master include: #include "tisp.hpp".
tisp/
├── includes/ Headers: node APIs, VirtualOp, SuperNode, utilities
│ ├── tisp.hpp Master include (all nodes + framework)
│ ├── TISP_virtualOp.hpp
│ └── TISP_*.hpp One header per node
├── src/
│ ├── AUDIOLIB/ 31 audio nodes
│ ├── DSPLIB/ 10 DSP nodes
│ ├── FFTLIB/ 3 FFT nodes
│ ├── MATHLIB/ 15 math nodes
│ ├── misc/ 4 utility nodes
│ ├── superNode/ SuperNode DMA implementations
│ └── common/ VirtualOp, L2BumpAllocator, profiler
├── test/ Mirrors src/ — one directory per node
│ └── common/ NodeFactory, UnitTestL2Heap, profiling, TI_compare_mem
├── cmake/
│ ├── c7x.cmake TI cl7x toolchain (target)
│ ├── gcc.cmake g++-11 toolchain (Linux host emulation)
│ ├── msvc.cmake MSVC 2022 toolchain (Windows host emulation)
│ ├── xlibs.cmake West workspace xlib ExternalProject integration
│ └── linkers/ Device linker scripts (C7100, C7120, C7504, C7524)
├── scripts/
│ └── west_ext.py west build-tisp extension command
├── ext_libs/ Pre-built xlib binaries (fallback, non-West builds)
├── west.yml West manifest — declares xlib sibling repos
├── west-commands.yml West extension command descriptor
└── CMakePresets.json All supported build configurations
TISP depends on four TI external libraries (xlibs): FFTLIB, DSPLIB, AUDIOLIB, MATHLIB. Two ways to provide them:
| Method | When to use |
|---|---|
| West workspace (recommended) | New setups, CI/CD, repo-first workflow |
| MCU+ SDK / PSDK_RTOS (legacy) | Existing SDK installs |
west.yml lives inside this repo (checked into git). West uses it as a
manifest — a recipe declaring which sibling repos to fetch and at which
revisions. The bootstrapping sequence is:
- You clone
tisp/manually with plaingit clone— this is the only step that requires you to know the repo URL. west init -l tisp/readswest.ymlfrom the already-cloned repo and creates a.west/configin the parent directory, promoting that directory to a West workspace root.west updatefetches every project declared in the manifest as siblings oftisp/at the pinned revisions.west build-tispruns cmake configure + build. CMake auto-detects the workspace, builds all xlibs in parallel, then builds TISP itself.
Two manifest files are provided — choose based on your needs:
| Manifest | Contents | MCU_PLUS_SDK_ROOT |
|---|---|---|
west.yml |
xlibs only | must be set via env (source ~/.c7x_env_c7504) |
dev.yml |
xlibs + full MCU+ SDK | auto-detected from workspace |
mkdir workspace && cd workspace
git clone ssh://git@bitbucket.itg.ti.com/xlib/tisp.git
pip install west
west init -l tisp/
west update # clones xlib/fftlib dsplib audiolib mathlib
source ~/.c7x_env_c7504 # sets CGT7X_ROOT, PATH, MCU_PLUS_SDK_ROOT
west build-tispOnly CGT7X_ROOT needed — MCU_PLUS_SDK_ROOT is auto-detected from the workspace.
One-time per machine — URL remapping for MCU SDK github mirrors:
git clone ssh://git@bitbucket.itg.ti.com/processor-sdk-mcu/mcupsdk_internal.git -b k3_main
echo '[include]' >> ~/.gitconfig
echo ' path = <workspace>/mcupsdk_internal/git_config/local_config.txt' >> ~/.gitconfigEvery new workspace:
mkdir workspace && cd workspace
git clone ssh://git@bitbucket.itg.ti.com/xlib/tisp.git
pip install west
west init -l tisp/ --mf dev.yml
west update # clones xlib/* + mcu_plus_sdk/ (dmautils, freertos, drivers...)
export CGT7X_ROOT=/path/to/ti-cgt-c7000_<version>
west build-tisp # MCU_PLUS_SDK_ROOT auto-set from workspaceOn build you will see:
-- West workspace: MCU_PLUS_SDK_ROOT auto-set to /path/to/workspace/mcu_plus_sdk
-- West workspace detected — xlibs will be built from source
...
Done — am62d built successfully.
Done — am275 built successfully.
west build-tisp # am62d + am275, pc, release, lib only
west build-tisp --soc am62d # single SOC
west build-tisp --type autotest # library + tests
west build-tisp --platform target # C7x target build
west build-tisp --build-type debug # debug
west build-tisp --preset release-autotest-am62d-pc # explicit preset overrideBuild directories are isolated per SOC and platform so switching between
host emulation and C7x target requires no --fresh:
tisp/build/
├── am62d/
│ ├── pc/ ← west build-tisp --soc am62d
│ └── target/ ← west build-tisp --soc am62d --platform target
└── am275/
├── pc/ ← west build-tisp --soc am275
└── target/ ← west build-tisp --soc am275 --platform target
Option A (west.yml):
workspace/
├── .west/config
├── tisp/
└── xlib/
├── fftlib/ ├── dsplib/ ├── audiolib/ └── mathlib/
Option B (dev.yml):
workspace/
├── .west/config
├── tisp/
├── xlib/
│ ├── fftlib/ ├── dsplib/ ├── audiolib/ └── mathlib/
└── mcu_plus_sdk/
└── source/
├── drivers/dmautils/
└── kernel/freertos/
A project that depends on TISP can import its manifest to get the full dependency tree transitively:
# downstream project's west.yml
projects:
- name: tisp
url: ssh://git@bitbucket.itg.ti.com/xlib/tisp.git
revision: dev
import: true # pulls in tisp/west.yml → fftlib, dsplib, audiolib, mathlibAfter west update, the downstream workspace has tisp/ and all four xlibs
as siblings. west build-tisp is also available to the downstream project.
export MCU_PLUS_SDK_ROOT=/path/to/freertos_sdk_<soc>_<version>
export CGT7X_ROOT=/path/to/ti-cgt-c7000_<version>
cmake -S . -B build --preset release-buildlib-am62d-pc --fresh
cmake --build build -jOn configure you will see:
-- Using MCU_PLUS_SDK xlibs (MCU_PLUS_SDK_ROOT = /path/to/sdk)
For J722S targets set PSDK_RTOS_ROOT instead of MCU_PLUS_SDK_ROOT.
cmake -S . --list-presets| Preset | Platform | SOC | Type |
|---|---|---|---|
release-autotest-am62d-pc |
Linux host | AM62D / C7504 | Full test suite |
debug-autotest-am62d-pc |
Linux host | AM62D / C7504 | Full test suite (debug) |
release-autotest-am275-pc |
Linux host | AM275 / C7524 | Full test suite |
release-buildlib-am62d-pc |
Linux host | AM62D / C7504 | Library only |
release-autotest-am62d-target |
C7x target | AM62D / C7504 | Full test suite |
release-autotest-am275-target |
C7x target | AM275 / C7524 | Full test suite |
| … |
| Artifact | Path |
|---|---|
| TISP static library | lib/release/TISP_<DEVICE>_x86_64.a (PC) |
| TISP static library | lib/release/TISP_<DEVICE>.lib (target) |
| Test binaries (PC) | bin/release/test_TISP_<name>_<DEVICE>_x86_64 |
| Test binaries (target) | bin/release/test_TISP_<name>_<DEVICE>.out |
| Platform | Compiler | C++ standard | Key defines |
|---|---|---|---|
| Linux host emulation | g++-11 | C++14 | HOST_EMULATION |
| Windows host emulation | MSVC 2022 | C++14 | HOST_EMULATION, WIN32 |
| C7x target | cl7x (TI CGT) | C++14 (--c++14) |
SOC-specific |
Use #if defined(HOST_EMULATION) to guard target-only code (DMA, L2SRAM sections, C7x intrinsics).
If a build fails with missing test_data/*.h:
cmake --build build --target=gen_all_test_case_headersBuild with an autotest preset, then run any binary from bin/release/:
cmake -S . -B build --preset release-autotest-am62d-pc --fresh
cmake --build build -j
./bin/release/test_TISP_fft1dBatched_C7504_x86_64
./bin/release/test_TISP_cascadeBiquad_C7504_x86_64
./bin/release/test_TISP_gain_C7504_x86_64Each test binary exercises create_graph() (builds the processing graph) and
execute_graph() (runs it and compares output against a reference).
Enforced by cmake/.clang-format:
| Rule | Value |
|---|---|
| Indent | 3 spaces |
| Column limit | 120 |
| Brace style | Stroustrup |
| Pointer alignment | Right (int *p) |
| Include guard | #pragma once (never #ifndef) |
- C++14 only —
--c++14on cl7x,-std=c++14on g++. No C++17 features. - Warnings are errors —
--emit_warnings_as_errors(target),-Werror(host). - Every node:
template <typename T> class Name final : public VirtualOp. - L2SRAM data:
__attribute__((section(".l2sramData"), aligned(128)))on target. - Test entry points:
void *create_graph()+void execute_graph(void *). - Never force-push
dev. - Feature branches:
feature/TISP-<N>-<short-description>branched fromdev.