276 lines
11 KiB
C
276 lines
11 KiB
C
/* SPDX-License-Identifier: AGPL-3.0-or-later */
|
|
/**
|
|
* @file resident_rope_compute.c
|
|
* @brief Compute third of the resident ROPE triad: rotary position embedding with no element
|
|
* indexing. The reader delivers four aligned tile streams -- activation (in), partner (rot),
|
|
* cos, and a sin table with the sign already folded in -- and per output tile:
|
|
*
|
|
* rotated column: out = in * cos + rot * sin
|
|
* pass-through column: out = in
|
|
*
|
|
* The FPU multiply cannot accumulate into DST here (a second multiply into the same DST tile
|
|
* overwrites it), so each product is packed to its own one-page scratch CB and the two are
|
|
* then added: three DST sections per rotated tile.
|
|
*
|
|
* Compiled three times (FT_TRISC_UNPACK / MATH / PACK); every hardware statement sits in one
|
|
* FT_TENSIX_<thread>(...) wrapper. Loop bounds come only from the descriptor, and after an
|
|
* abort every pop / acquire / commit / push still runs so the threads stay balanced.
|
|
*
|
|
* Compile-time args: 0 cb_in, 1 cb_rot, 2 cb_cos, 3 cb_sin, 4 cb_prod_cos, 5 cb_prod_sin,
|
|
* 6 cb_out, 7 wait_mode (0 upstream, 1 stoppable, 2 bound-only).
|
|
*
|
|
* Build:
|
|
* CTARGS=0,1,2,3,4,5,16,1 CB_TABLE=kernels/cb_tables/rope_float16b.cbtable \
|
|
* bash foundry/tt/build_tensix_kernel.sh \
|
|
* foundry/tt/kernels/resident_rope_compute.c out/ttk_rope
|
|
*
|
|
* @status Clean-room rewrite (plan Phase 4.7).
|
|
* @issues None known.
|
|
* @todo None
|
|
*/
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
|
|
#include "ft_tensix_cb_formats.h"
|
|
#include "ft_tensix_compute.h"
|
|
#include "ft_tensix_compute_cb.h"
|
|
#include "ft_tensix_kernel_args.h"
|
|
#include "ft_tensix_compute_sfpu.h"
|
|
#ifdef FT_TRISC_MATH
|
|
#include "ft_tensix_compute_math.h"
|
|
#endif
|
|
#ifdef FT_TRISC_UNPACK
|
|
#include "ft_tensix_compute_unpack.h"
|
|
#endif
|
|
#ifdef FT_TRISC_PACK
|
|
#include "ft_tensix_compute_pack.h"
|
|
#endif
|
|
|
|
#include "resident_queue_protocol.h"
|
|
#include "resident_rope_protocol.h"
|
|
|
|
#define cb_in ft_tensix_compile_time_arg(0)
|
|
#define cb_rot ft_tensix_compile_time_arg(1)
|
|
#define cb_cos ft_tensix_compile_time_arg(2)
|
|
#define cb_sin ft_tensix_compile_time_arg(3)
|
|
#define cb_prod_cos ft_tensix_compile_time_arg(4)
|
|
#define cb_prod_sin ft_tensix_compile_time_arg(5)
|
|
#define cb_out ft_tensix_compile_time_arg(6)
|
|
#define wait_mode ft_tensix_compile_time_arg(7)
|
|
|
|
enum { dst_register = 0 };
|
|
|
|
/* ===== Compute verbs (thread order inside each is fixed) ================================ */
|
|
|
|
/** One-time unit setup: A -> SrcA, B -> SrcB, packer configured for `out`. */
|
|
static FT_BH_INLINE void rope_hw_startup(uint32_t a, uint32_t b, uint32_t out)
|
|
{
|
|
(void)a;
|
|
(void)b;
|
|
(void)out;
|
|
FT_TENSIX_UNPACK(ft_tensix_unpack_hw_configure_ab(
|
|
ft_cb_unpack_src_format[a], ft_cb_unpack_src_format[b], ft_cb_unpack_dst_format[a],
|
|
ft_cb_unpack_dst_format[b], ft_cb_unpack_tile_face_rows[a], ft_cb_unpack_tile_face_rows[b],
|
|
ft_cb_unpack_tile_num_faces[a], ft_cb_unpack_tile_num_faces[b],
|
|
ft_tensix_cb(a)->fifo_page_size, ft_tensix_cb(b)->fifo_page_size));
|
|
FT_TENSIX_MATH(ft_tensix_math_pack_sync_init());
|
|
FT_TENSIX_MATH(ft_tensix_math_hw_configure(ft_cb_unpack_dst_format[a],
|
|
ft_cb_unpack_dst_format[b], FT_CB_DST_ACCUM_FP32));
|
|
FT_TENSIX_PACK(ft_tensix_pack_hw_configure(
|
|
ft_cb_pack_src_format[out], ft_cb_pack_dst_format[out], ft_tensix_cb(out)->fifo_page_size,
|
|
ft_cb_pack_tile_num_faces[out], ft_cb_pack_partial_face[out], 0 /* relu */,
|
|
FT_CB_DST_ACCUM_FP32));
|
|
FT_TENSIX_PACK(ft_tensix_pack_init(ft_cb_pack_src_format[out], ft_cb_pack_tile_face_rows[out],
|
|
ft_cb_pack_tile_num_faces[out], 1));
|
|
FT_TENSIX_PACK(ft_tensix_pack_dest_init());
|
|
}
|
|
|
|
/** Multiply init: MATH first, then UNPACK; geometry from `a` only. */
|
|
static FT_BH_INLINE void rope_mul_init(uint32_t a, uint32_t b)
|
|
{
|
|
(void)a;
|
|
(void)b;
|
|
FT_TENSIX_MATH(ft_tensix_math_eltwise_binary_mul_init(FT_CB_MATH_FIDELITY,
|
|
ft_cb_unpack_tile_face_rows[a]));
|
|
FT_TENSIX_UNPACK(ft_tensix_unpack_ab_init(ft_cb_unpack_tile_face_rows[a],
|
|
ft_cb_unpack_num_face_rows[a],
|
|
ft_cb_unpack_num_face_cols[a]));
|
|
}
|
|
|
|
/** Multiply the front tiles of `a` and `b` into DST. */
|
|
static FT_BH_INLINE void rope_mul_apply(uint32_t a, uint32_t b)
|
|
{
|
|
(void)a;
|
|
(void)b;
|
|
FT_TENSIX_UNPACK(ft_tensix_unpack_ab(a, b, 0, 0));
|
|
FT_TENSIX_MATH(ft_tensix_math_eltwise_binary_mul(
|
|
dst_register, (uint32_t)ft_cb_unpack_num_face_rows[a] * ft_cb_unpack_num_face_cols[a],
|
|
ft_cb_unpack_tile_face_rows[a]));
|
|
}
|
|
|
|
/** Add init (lowest fidelity): MATH first, then UNPACK; geometry from `a` only. */
|
|
static FT_BH_INLINE void rope_add_init(uint32_t a, uint32_t b)
|
|
{
|
|
(void)a;
|
|
(void)b;
|
|
FT_TENSIX_MATH(ft_tensix_math_eltwise_binary_addsub_init(
|
|
FT_BH_ENC_ELWADD(0, 0, FT_BH_ELWADD_SRCB_NO_BCAST, FT_BH_ADDR_MOD_0, 0),
|
|
(uint32_t)ft_cb_unpack_tile_num_faces[a], (uint32_t)ft_cb_unpack_tile_face_rows[a]));
|
|
FT_TENSIX_UNPACK(ft_tensix_unpack_ab_init(ft_cb_unpack_tile_face_rows[a],
|
|
ft_cb_unpack_num_face_rows[a],
|
|
ft_cb_unpack_num_face_cols[a]));
|
|
}
|
|
|
|
/** Add the front tiles of `a` and `b` into DST. */
|
|
static FT_BH_INLINE void rope_add_apply(uint32_t a, uint32_t b)
|
|
{
|
|
(void)a;
|
|
(void)b;
|
|
FT_TENSIX_UNPACK(ft_tensix_unpack_ab(a, b, 0, 0));
|
|
FT_TENSIX_MATH(ft_tensix_math_eltwise_binary_addsub(dst_register));
|
|
}
|
|
|
|
/** Copy init: UNPACK first, then MATH. */
|
|
static FT_BH_INLINE void rope_copy_init(uint32_t cb)
|
|
{
|
|
(void)cb;
|
|
FT_TENSIX_UNPACK(ft_tensix_unpack_a_init(
|
|
ft_cb_unpack_tile_face_rows[cb],
|
|
(uint32_t)ft_cb_unpack_num_face_rows[cb] * ft_cb_unpack_num_face_cols[cb]));
|
|
FT_TENSIX_MATH(ft_tensix_math_datacopy_init((uint32_t)ft_cb_unpack_num_face_rows[cb] *
|
|
ft_cb_unpack_num_face_cols[cb]));
|
|
}
|
|
|
|
/** Copy one tile of `cb` into DST. */
|
|
static FT_BH_INLINE void rope_copy_apply(uint32_t cb)
|
|
{
|
|
(void)cb;
|
|
FT_TENSIX_UNPACK(ft_tensix_unpack_a(cb, 0));
|
|
FT_TENSIX_MATH(ft_tensix_math_datacopy(dst_register));
|
|
}
|
|
|
|
/* ===== Steps ============================================================================ */
|
|
|
|
/** Hand DST to PACK and pack it as one page of `cb`. */
|
|
static void commit_dst_to(ftq_context *ctx, uint32_t cb)
|
|
{
|
|
FT_TENSIX_MATH(ft_tensix_math_dest_section_done());
|
|
(void)ftq_cb_reserve_back_stoppable(ctx, (int32_t)cb, 1, wait_mode);
|
|
FT_TENSIX_PACK(ft_tensix_packer_wait_for_math_done());
|
|
FT_TENSIX_PACK(ft_tensix_pack_tile(dst_register, cb));
|
|
FT_TENSIX_PACK(ft_tensix_pack_dest_section_done(FT_CB_DST_ACCUM_FP32));
|
|
FT_TENSIX_PACK(ft_tensix_compute_cb_push_back(cb, 1));
|
|
}
|
|
|
|
/** destination <- a * b, one tile. */
|
|
static void multiply_into(ftq_context *ctx, uint32_t a, uint32_t b, uint32_t destination)
|
|
{
|
|
rope_mul_init(a, b);
|
|
FT_TENSIX_MATH(ft_tensix_math_wait_for_dest_available());
|
|
rope_mul_apply(a, b);
|
|
commit_dst_to(ctx, destination);
|
|
}
|
|
|
|
/** out <- in * cos + rot * sin, one tile, through the two product CBs. */
|
|
static void rotate_one_tile(ftq_context *ctx)
|
|
{
|
|
multiply_into(ctx, cb_in, cb_cos, cb_prod_cos);
|
|
multiply_into(ctx, cb_rot, cb_sin, cb_prod_sin);
|
|
(void)ftq_cb_wait_front_stoppable(ctx, (int32_t)cb_prod_cos, 1, wait_mode);
|
|
(void)ftq_cb_wait_front_stoppable(ctx, (int32_t)cb_prod_sin, 1, wait_mode);
|
|
rope_add_init(cb_prod_cos, cb_prod_sin);
|
|
FT_TENSIX_MATH(ft_tensix_math_wait_for_dest_available());
|
|
rope_add_apply(cb_prod_cos, cb_prod_sin);
|
|
commit_dst_to(ctx, cb_out);
|
|
FT_TENSIX_UNPACK(ft_tensix_compute_cb_pop_front(cb_prod_cos, 1));
|
|
FT_TENSIX_UNPACK(ft_tensix_compute_cb_pop_front(cb_prod_sin, 1));
|
|
}
|
|
|
|
/** out <- in, one tile. */
|
|
static void copy_one_tile(ftq_context *ctx)
|
|
{
|
|
rope_copy_init(cb_in);
|
|
FT_TENSIX_MATH(ft_tensix_math_wait_for_dest_available());
|
|
rope_copy_apply(cb_in);
|
|
commit_dst_to(ctx, cb_out);
|
|
}
|
|
|
|
/** Run one ROPE descriptor; an unsupported shape is refused before any CB traffic. */
|
|
static void compute_one_rope(ftq_context *ctx, volatile FTQ_L1_PTR uint32_t *parameters)
|
|
{
|
|
const uint32_t tile_count = parameters[kRopeTileCount];
|
|
const uint32_t head_tiles = parameters[kRopeHeadTiles];
|
|
const uint32_t rot_tiles = parameters[kRopeRotTiles];
|
|
uint32_t tile;
|
|
|
|
if (!ftr_shape_is_supported(head_tiles, rot_tiles) || tile_count == 0u ||
|
|
tile_count % head_tiles != 0u) {
|
|
ftq_abort(ctx, kErrBadParameters);
|
|
return;
|
|
}
|
|
|
|
for (tile = 0; tile < tile_count; tile++) {
|
|
const uint32_t column = tile % head_tiles;
|
|
const bool rotated = (column < rot_tiles);
|
|
|
|
(void)ftq_cb_wait_front_stoppable(ctx, (int32_t)cb_in, 1, wait_mode);
|
|
if (rotated) {
|
|
(void)ftq_cb_wait_front_stoppable(ctx, (int32_t)cb_rot, 1, wait_mode);
|
|
(void)ftq_cb_wait_front_stoppable(ctx, (int32_t)cb_cos, 1, wait_mode);
|
|
(void)ftq_cb_wait_front_stoppable(ctx, (int32_t)cb_sin, 1, wait_mode);
|
|
rotate_one_tile(ctx);
|
|
} else {
|
|
copy_one_tile(ctx);
|
|
}
|
|
FT_TENSIX_UNPACK(ft_tensix_compute_cb_pop_front(cb_in, 1));
|
|
if (rotated) {
|
|
FT_TENSIX_UNPACK(ft_tensix_compute_cb_pop_front(cb_rot, 1));
|
|
FT_TENSIX_UNPACK(ft_tensix_compute_cb_pop_front(cb_cos, 1));
|
|
FT_TENSIX_UNPACK(ft_tensix_compute_cb_pop_front(cb_sin, 1));
|
|
}
|
|
}
|
|
}
|
|
|
|
void kernel_main(void)
|
|
{
|
|
ftq_context ctx;
|
|
bool running = true;
|
|
|
|
ftq_context_init(&ctx);
|
|
ftq_status_set(&ctx, kStateBoot);
|
|
if (!ftq_check_control(&ctx)) {
|
|
ftq_status_set(&ctx, kStateExit);
|
|
return;
|
|
}
|
|
|
|
/* Once: cb_in and cb_cos are the A/B pair the unpacker is configured for. */
|
|
rope_hw_startup(cb_in, cb_cos, cb_out);
|
|
|
|
ctx.cursor = ctx.control[kFieldCompletedCount];
|
|
while (running) {
|
|
volatile FTQ_L1_PTR uint32_t *descriptor;
|
|
uint32_t opcode;
|
|
|
|
if (!ftq_wait_for_work(&ctx, kFieldHead))
|
|
break;
|
|
ctx.aborting = false;
|
|
ftq_status_set(&ctx, kStateExec);
|
|
|
|
descriptor = ftq_descriptor(&ctx);
|
|
opcode = descriptor[kDescOpcode];
|
|
ftq_status_opcode(&ctx, opcode);
|
|
if (opcode == kOpRope) {
|
|
ftq_status_set(&ctx, kStateCbWaitFront);
|
|
compute_one_rope(&ctx, ftq_parameters(descriptor));
|
|
ftq_status_set(&ctx, kStateExec);
|
|
if (ctx.aborting)
|
|
running = false;
|
|
} else if (opcode == kOpStop) {
|
|
running = false;
|
|
}
|
|
if (!ctx.aborting)
|
|
ctx.cursor++;
|
|
}
|
|
ftq_status_set(&ctx, kStateExit);
|
|
}
|