102 lines
4.2 KiB
C
102 lines
4.2 KiB
C
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
//
|
|
// ft_tt_memory_device_shim.c
|
|
// A flat C API over the arithmetic half of kernels/resident_memory_protocol.h, so the
|
|
// OFF-HARDWARE suite exercises THE KERNEL'S OWN FUNCTIONS instead of a C transcription of
|
|
// them.
|
|
//
|
|
// THIS FILE WAS C++ UNTIL 2026-08-13, AND ONLY FOR LINKAGE. The protocol header was C++,
|
|
// so reaching the kernel's own inline functions from a C suite needed an `extern "C"`
|
|
// wrapper. Phase 6.6 made that header C99, the linkage reason evaporated, and this is now
|
|
// plain C. What it still earns its place for is the FLATTENING at the bottom: `ftm_run`
|
|
// becomes two parallel arrays, so the suite needs no struct of the kernel's.
|
|
//
|
|
// THIS IS THE DIFFERENCE BETWEEN TESTING THE KERNEL AND TESTING A COPY OF IT. Face order
|
|
// is the trap docs/tt_kernel_model.md §9 exists for, and it is invisible to any metric
|
|
// computed through the same wrong code — so a test that re-implements the chunk offsets
|
|
// in C and compares them with the kernel's would agree with itself. Here the suite calls
|
|
// the real inline functions and scores them against ft_tt_tilize.c, which was written for
|
|
// another purpose entirely and is verified against tt-metal's own tilize_utils.cpp.
|
|
//
|
|
// It compiles because resident_memory_protocol.h was written to be compilable: it
|
|
// includes <stdint.h>/<stdbool.h> and nothing else, names no device API, and touches no
|
|
// L1 pointer. That is a property to KEEP — the moment it needs the stock dataflow API, this shim
|
|
// stops building and the off-hardware gate loses the only part of the kernel it can see.
|
|
//
|
|
// Status: built by tests/Makefile.memory as part of the off-hardware gate.
|
|
// Issues: None
|
|
// Todo: None
|
|
|
|
#include "../kernels/resident_memory_protocol.h"
|
|
|
|
|
|
uint32_t ft_tt_device_chunk_bytes(uint32_t tile_bytes)
|
|
{
|
|
return ftm_chunk_bytes(tile_bytes);
|
|
}
|
|
|
|
uint32_t ft_tt_device_face_bytes(uint32_t tile_bytes)
|
|
{
|
|
return ftm_face_bytes(tile_bytes);
|
|
}
|
|
|
|
uint32_t ft_tt_device_chunk_offset(uint32_t row, uint32_t half, uint32_t tile_bytes)
|
|
{
|
|
return ftm_chunk_offset(row, half, tile_bytes);
|
|
}
|
|
|
|
uint32_t ft_tt_device_group_row_bytes(uint32_t group_tiles, uint32_t tile_bytes)
|
|
{
|
|
return ftm_group_row_bytes(group_tiles, tile_bytes);
|
|
}
|
|
|
|
void ft_tt_device_place_row_from_row_major(uint32_t* destination_block, const uint32_t* source_row,
|
|
uint32_t destination_row, uint32_t group_tiles,
|
|
uint32_t tile_bytes)
|
|
{
|
|
ftm_place_row_from_row_major(destination_block, source_row, destination_row, group_tiles,
|
|
tile_bytes);
|
|
}
|
|
|
|
void ft_tt_device_place_row_from_tiles(uint32_t* destination_block, const uint32_t* source_block,
|
|
uint32_t source_row, uint32_t destination_row,
|
|
uint32_t group_tiles, uint32_t tile_bytes)
|
|
{
|
|
ftm_place_row_from_tiles(destination_block, source_block, source_row, destination_row,
|
|
group_tiles, tile_bytes);
|
|
}
|
|
|
|
void ft_tt_device_zero_words(uint32_t* destination, uint32_t words)
|
|
{
|
|
ftm_zero_words(destination, words);
|
|
}
|
|
|
|
/** The runs, flattened into two parallel arrays so the C side needs no struct of the
|
|
* kernel's. `offsets` and `bytes` must hold kMemMaxRuns entries each. */
|
|
uint32_t ft_tt_device_destination_runs(uint32_t row0, uint32_t row_count, uint32_t tile_bytes,
|
|
uint32_t* offsets, uint32_t* bytes)
|
|
{
|
|
ftm_run runs[kMemMaxRuns];
|
|
const uint32_t count = ftm_destination_runs(row0, row_count, tile_bytes, runs);
|
|
|
|
for (uint32_t index = 0; index < count; index++) {
|
|
offsets[index] = runs[index].offset;
|
|
bytes[index] = runs[index].bytes;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
uint32_t ft_tt_device_max_runs(void)
|
|
{
|
|
return kMemMaxRuns;
|
|
}
|
|
|
|
/** The zero-length guard itself, so the suite can assert the kernel HAS one rather than
|
|
* trusting a comment. A zero-length NoC read is suspected of taking the whole card down
|
|
* (resident_memory_protocol.h), so the guard is load-bearing rather than defensive. */
|
|
int ft_tt_device_length_is_issuable(uint32_t bytes)
|
|
{
|
|
return ftm_length_is_issuable(bytes) ? 1 : 0;
|
|
}
|
|
|