Foundry/tt/tools/dump_tensix_kernel_header.c

105 lines
3.8 KiB
C

/* SPDX-License-Identifier: AGPL-3.0-or-later */
/* Copyright (C) 2026 David (Corey) Herrera */
/**
* @file dump_tensix_kernel_header.c
* @brief Round-trip check for the generated ft_tt_kernels.h: parse every embedded image
* with ft_tt_elf_parse() and print what the parser found, in a format that can be
* diffed byte-for-byte against readelf's view of the same ELFs.
*
* The point is that the comparison is against the TOOLCHAIN, not against ourselves.
* tools/readelf_tensix_kernel_dump.sh emits the identical format straight out of
* riscv-tt-elf-readelf; `diff` between the two is the whole test. A parser bug and a
* generator bug that happened to agree would still show up, because readelf agrees
* with neither.
*
* Build (from foundry/tt/tools):
* cc -std=c99 -Wall -Wextra -Werror -pedantic -I.. -o /tmp/dump_kernels \
* dump_tensix_kernel_header.c ../ft_tt_elf.c ../ft_tt_kernel_blob.c \
* ../ft_tt_device.c ../ft_tt_kmd.c ../ft_tt_tlb.c
*
* Lines beginning with '#' are metadata that only the header knows (program name,
* toolchain, source .cpp); strip them before diffing.
*
* @status Run on the p150a card host 2026-08-11 against the committed ft_tt_kernels.h; its output
* matched readelf_tensix_kernel_dump.sh exactly.
* @issues None
* @todo None
*/
#include <stdio.h>
#include "ft_tt_device.h"
#include "ft_tt_elf.h"
#include "ft_tt_kernel_blob.h"
#include "ft_tt_kernels.h"
#include "ft_tt_memmap.h"
static const char *processor_name(unsigned processor)
{
switch (processor) {
case FT_TT_PROC_DM0: return "DM0";
case FT_TT_PROC_DM1: return "DM1";
case FT_TT_PROC_MATH0: return "MATH0";
case FT_TT_PROC_MATH1: return "MATH1";
case FT_TT_PROC_MATH2: return "MATH2";
default: return "UNKNOWN";
}
}
/** Parse one embedded image and print its toolchain-comparable description.
* @return 0 on success, 1 if the parser rejected the blob. */
static int dump_image(const ft_tt_kernel_image *image)
{
const char *name = processor_name(image->processor);
ft_tt_elf_image parsed = {0};
uint32_t low = 0;
uint32_t high = 0;
unsigned index;
printf("# image %s source %s elf_bytes %zu\n", name, image->source_name, image->elf_size);
if (ft_tt_elf_parse(image->elf_data, image->elf_size, &parsed) != FT_TT_OK) {
printf("%s PARSE_FAILED\n", name);
return 1;
}
if (ft_tt_elf_load_extent(&parsed, &low, &high) != FT_TT_OK) {
printf("%s EXTENT_FAILED\n", name);
return 1;
}
printf("%s entry=0x%08x\n", name, parsed.entry_address);
for (index = 0; index < parsed.segment_count; index++) {
const ft_tt_elf_segment *segment = &parsed.segments[index];
printf("%s seg%u exec=0x%08x load=0x%08x file=%u mem=%u\n", name, index,
segment->exec_address, segment->load_address, segment->file_bytes,
segment->memory_bytes);
}
printf("# %s loaded_bytes %u l1_extent 0x%08x..0x%08x\n", name, parsed.loaded_bytes, low,
high);
return 0;
}
int main(void)
{
unsigned failures = 0;
unsigned program_index;
for (program_index = 0; program_index < FT_TT_KERNEL_PROGRAM_COUNT; program_index++) {
const ft_tt_kernel_program *program = ft_tt_kernel_programs[program_index];
unsigned image_index;
printf("# program %s toolchain %s ctargs %s images %u enables 0x%x\n", program->name,
program->toolchain, program->compile_time_args, program->image_count,
ft_tt_kernel_program_enables(program));
for (image_index = 0; image_index < program->image_count; image_index++)
failures += (unsigned)dump_image(&program->images[image_index]);
}
if (failures) {
fprintf(stderr, "dump_tensix_kernel_header: %u image(s) failed to parse\n", failures);
return 1;
}
return 0;
}