196 lines
7.5 KiB
Makefile
196 lines
7.5 KiB
Makefile
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
# Copyright (C) 2026 David (Corey) Herrera
|
|
# Foundry Blackhole backend — Phase 1a tests.
|
|
#
|
|
# The device test is READ-ONLY against the card. It runs only on the card host
|
|
# (the card host); on any other machine `make check` refuses instead of failing.
|
|
#
|
|
# Two build modes:
|
|
# make Phase 1a. The NoC fence is CLOSED: CONFIGURE_TLB cannot be
|
|
# issued, TLB apertures map PROT_NONE, and the TLB register
|
|
# file maps read-only.
|
|
# make PHASE1B=1 Opens the fence. DO NOT USE UNSUPERVISED — this is what
|
|
# lets a wrong NoC coordinate hang the card (spec §7.3).
|
|
#
|
|
# `make red` exists because a green test nobody has watched fail is not
|
|
# evidence (coding-best-practices.md §9). It rebuilds from scratch each time:
|
|
# Apple ships GNU make 3.81, whose one-second mtime granularity silently skips
|
|
# a rebuild of a source edited in the same second as its object, so a mutation
|
|
# loop that relies on incremental make can be testing the PREVIOUS binary.
|
|
|
|
CC ?= cc
|
|
SRC_DIR := ..
|
|
|
|
# The on-card harness opens the card through the product transport seam.
|
|
include hardware_session_sources.mk
|
|
BUILD := build
|
|
|
|
CFLAGS := -std=c99 -O1 -g \
|
|
-Wall -Wextra -Werror -pedantic \
|
|
-Wshadow -Wconversion -Wstrict-prototypes -Wformat=2 \
|
|
-fstack-protector-strong \
|
|
-I$(SRC_DIR)
|
|
|
|
# Header dependency tracking. Without it, editing a HEADER rebuilds nothing and
|
|
# the link silently mixes objects compiled against two different struct layouts
|
|
# — which is not a build error, it is a wrong offset and a segfault (or worse, a
|
|
# wrong answer). Adding a field to ft_tt_grid_info reproduced exactly that on
|
|
# 2026-08-12. `-MMD -MP` makes every .o depend on the headers it read.
|
|
DEPFLAGS := -MMD -MP
|
|
|
|
|
|
ifdef PHASE1B
|
|
CFLAGS += -DFT_TT_PHASE1B_NOC_ENABLED
|
|
endif
|
|
|
|
SOURCES := $(SRC_DIR)/ft_tt_kmd.c \
|
|
$(SRC_DIR)/ft_tt_arch.c \
|
|
$(SRC_DIR)/ft_tt_arch_blackhole.c \
|
|
$(SRC_DIR)/ft_tt_device.c \
|
|
$(SRC_DIR)/ft_tt_tlb.c \
|
|
$(SRC_DIR)/ft_tt_coord.c \
|
|
$(SRC_DIR)/ft_tt_arc_telemetry.c \
|
|
test_device.c
|
|
|
|
OBJECTS := $(sort $(addprefix $(BUILD)/,$(notdir $(SOURCES:.c=.o))))
|
|
TARGET := $(BUILD)/test_device
|
|
|
|
# Phase 2 run control. Runs ANYWHERE — it needs no card, because every device touch
|
|
# goes through the ft_tt_noc_access vtable and the test supplies a simulated Tensix.
|
|
LAUNCH_SOURCES := $(SRC_DIR)/ft_tt_kmd.c \
|
|
$(SRC_DIR)/ft_tt_arch.c \
|
|
$(SRC_DIR)/ft_tt_arch_blackhole.c \
|
|
$(SRC_DIR)/ft_tt_device.c \
|
|
$(SRC_DIR)/ft_tt_tlb.c \
|
|
$(SRC_DIR)/ft_tt_coord.c \
|
|
$(SRC_DIR)/ft_tt_noc.c \
|
|
$(SRC_DIR)/ft_tt_buffer.c \
|
|
$(SRC_DIR)/ft_tt_elf.c \
|
|
$(SRC_DIR)/ft_tt_kernel_blob.c \
|
|
$(SRC_DIR)/ft_tt_udrv_claim.c \
|
|
$(SRC_DIR)/ft_tt_tensix_claim.c \
|
|
$(SRC_DIR)/ft_tt_launch.c \
|
|
ft_tt_phase2_l1_layout.c \
|
|
test_launch.c
|
|
|
|
LAUNCH_OBJECTS := $(sort $(addprefix $(BUILD)/,$(notdir $(LAUNCH_SOURCES:.c=.o))))
|
|
LAUNCH_TARGET := $(BUILD)/test_launch
|
|
|
|
# Phase 2 ON-CARD checklists — docs/tt_launch_notes.md §6 steps 5-13, one binary per
|
|
# group of steps. These need the card AND the NoC fence open, so they are built only
|
|
# with PHASE2=1 and refuse to build without PHASE1B. Firmware ELFs come from
|
|
# FT_TT_FIRMWARE_DIRECTORY at run time; the kernels are embedded in ft_tt_kernels.h.
|
|
PHASE2_BACKEND := $(SRC_DIR)/ft_tt_kmd.c \
|
|
$(SRC_DIR)/ft_tt_arch.c \
|
|
$(SRC_DIR)/ft_tt_arch_blackhole.c \
|
|
$(SRC_DIR)/ft_tt_device.c \
|
|
$(SRC_DIR)/ft_tt_tlb.c \
|
|
$(SRC_DIR)/ft_tt_arc_telemetry.c \
|
|
$(SRC_DIR)/ft_tt_coord.c \
|
|
$(SRC_DIR)/ft_tt_noc.c \
|
|
$(SRC_DIR)/ft_tt_elf.c \
|
|
$(SRC_DIR)/ft_tt_kernel_blob.c \
|
|
$(SRC_DIR)/ft_tt_udrv_claim.c \
|
|
$(SRC_DIR)/ft_tt_tensix_claim.c \
|
|
$(SRC_DIR)/ft_tt_launch.c
|
|
|
|
PHASE2_SUPPORT := ft_tt_test_report.c $(HARDWARE_SESSION_SOURCES) ft_tt_phase2_l1_layout.c
|
|
|
|
PHASE2_PROGRAMS := test_phase2_boot test_phase2_images test_phase2_launch \
|
|
test_phase2_vector_add test_phase2_multicore
|
|
|
|
PHASE2_TARGETS := $(addprefix $(BUILD)/,$(PHASE2_PROGRAMS))
|
|
|
|
# Phase 3 tile layout. Pure arithmetic, runs anywhere, needs nothing.
|
|
TILIZE_SOURCES := $(SRC_DIR)/ft_tt_tilize.c test_tilize.c
|
|
TILIZE_TARGET := $(BUILD)/test_tilize
|
|
|
|
# Phase 7 row-0-only transfers. Runs anywhere: a simulated DRAM bank stands in for the
|
|
# accessor and enforces the real 64 B read / 16 B write alignment, so a mutation that asks
|
|
# for a 32 B read is refused here exactly as the card refuses it. ft_tt_noc.c is linked for
|
|
# its transfer checks — the proof that the bulk path cannot carry a register access.
|
|
ROW0_SOURCES := $(SRC_DIR)/ft_tt_kmd.c \
|
|
$(SRC_DIR)/ft_tt_arch.c \
|
|
$(SRC_DIR)/ft_tt_arch_blackhole.c \
|
|
$(SRC_DIR)/ft_tt_device.c \
|
|
$(SRC_DIR)/ft_tt_tlb.c \
|
|
$(SRC_DIR)/ft_tt_coord.c \
|
|
$(SRC_DIR)/ft_tt_noc.c \
|
|
$(SRC_DIR)/ft_tt_tilize.c \
|
|
$(SRC_DIR)/ft_tt_tile_row0.c \
|
|
test_tile_row0.c
|
|
ROW0_TARGET := $(BUILD)/test_tile_row0
|
|
|
|
.PHONY: all check red check-launch red-launch check-tilize red-tilize check-row0 red-row0 \
|
|
phase2 clean
|
|
|
|
all: $(TARGET) $(LAUNCH_TARGET) $(TILIZE_TARGET) $(ROW0_TARGET)
|
|
|
|
$(BUILD):
|
|
mkdir -p $(BUILD)
|
|
|
|
$(BUILD)/%.o: $(SRC_DIR)/%.c | $(BUILD)
|
|
$(CC) $(CFLAGS) $(DEPFLAGS) -c $< -o $@
|
|
|
|
$(BUILD)/%.o: %.c | $(BUILD)
|
|
$(CC) $(CFLAGS) $(DEPFLAGS) -c $< -o $@
|
|
|
|
$(TARGET): $(OBJECTS)
|
|
$(CC) $(CFLAGS) $(OBJECTS) -o $@
|
|
|
|
$(LAUNCH_TARGET): $(LAUNCH_OBJECTS)
|
|
$(CC) $(CFLAGS) $(LAUNCH_OBJECTS) -o $@
|
|
|
|
# Whole-program build: see the note on the Phase 2 rule below.
|
|
$(TILIZE_TARGET): $(TILIZE_SOURCES) | $(BUILD)
|
|
$(CC) $(CFLAGS) $(TILIZE_SOURCES) -o $@
|
|
|
|
# Whole-program too, for the same reason, and because run_tile_row0_red.sh rebuilds it
|
|
# against a mutated copy of the source and must never link a stale object of the original.
|
|
$(ROW0_TARGET): $(ROW0_SOURCES) | $(BUILD)
|
|
$(CC) $(CFLAGS) $(ROW0_SOURCES) -o $@
|
|
|
|
# One direct cc per program: these are whole-program builds on purpose, so the GNU make
|
|
# 3.81 same-second staleness trap (best-practices §9) cannot serve a stale object.
|
|
$(BUILD)/test_phase2_%: test_phase2_%.c $(PHASE2_BACKEND) $(PHASE2_SUPPORT) | $(BUILD)
|
|
ifndef PHASE1B
|
|
$(error Phase 2 hardware tests need PHASE1B=1 — they drive the NoC)
|
|
endif
|
|
$(CC) $(CFLAGS) $(PHASE2_BACKEND) $(PHASE2_SUPPORT) $< -o $@
|
|
|
|
# Build every on-card checklist binary. Running them is deliberately NOT a make target:
|
|
# they drive silicon and belong in a supervised, detached run.
|
|
phase2: $(PHASE2_TARGETS)
|
|
|
|
check: $(TARGET)
|
|
@test -c /dev/tenstorrent/0 || { \
|
|
echo "no /dev/tenstorrent/0 — this test needs the card host"; exit 77; }
|
|
./$(TARGET)
|
|
|
|
check-launch: $(LAUNCH_TARGET)
|
|
./$(LAUNCH_TARGET)
|
|
|
|
# Full rebuild, then run. Use this for every red/green pass.
|
|
red: clean $(TARGET)
|
|
-./$(TARGET)
|
|
|
|
red-launch: clean $(LAUNCH_TARGET)
|
|
-./$(LAUNCH_TARGET)
|
|
|
|
check-tilize: $(TILIZE_TARGET)
|
|
./$(TILIZE_TARGET)
|
|
|
|
red-tilize: clean $(TILIZE_TARGET)
|
|
-./$(TILIZE_TARGET)
|
|
|
|
check-row0: $(ROW0_TARGET)
|
|
./$(ROW0_TARGET)
|
|
|
|
red-row0: clean $(ROW0_TARGET)
|
|
-./$(ROW0_TARGET)
|
|
|
|
clean:
|
|
rm -rf $(BUILD)
|
|
|
|
-include $(wildcard $(BUILD)/*.d)
|