Foundry/tt/kernels/ft_tensix_compute_matmul.h

375 lines
19 KiB
C

/* SPDX-License-Identifier: AGPL-3.0-or-later */
/* Copyright (C) 2026 David (Corey) Herrera */
/**
* @file ft_tensix_compute_matmul.h
* @brief Tile matrix multiply for the MATH and UNPACK threads: address-modifier programming,
* replay-buffer recording, MOP templates and per-tile issue.
*
* MATH: a 32x32 by 32x32 tile product is 16 MVMULs (WormholeB0/TensixTile/TensixCoprocessor/
* MVMUL.md), each consuming 8 rows; their SrcA/SrcB/Dst walk is encoded in address-modifier
* slots 0, 1, 2, 4 and 5 (RWCs.md, slot 5 also advances the fidelity phase). The 16 MVMULs
* are recorded once into the replay buffer (REPLAY.md) and the MOP loop instruction replays
* them (MOPExpander.md). A 16-row in0 variant uses 8 MVMULs.
*
* UNPACK: a 12-instruction program is recorded into the replay buffer, two 6-instruction
* halves, one per unpacker config context. Each half unpacks SrcA, then advances unpacker 0's
* L1 base address by the A tile size (GPR 36) so the MOP can walk the K dimension. The
* operands are deliberately crossed: in0 goes to SrcB (unpacker 1) and in1 to SrcA
* (unpacker 0), since the FPU computes SrcB x SrcA.
*
* Replay slots: [0, 16) belong to the UNPACK program and the SFPU, [16, 32) to the MATH
* thread's FPU sequences (Foundry convention). GPR numbers are Foundry conventions.
*
* @status Clean-room rewrite (plan Phase 4, step 4.5b).
* @issues None
* @todo None
*/
#ifndef FT_TENSIX_COMPUTE_MATMUL_H
#define FT_TENSIX_COMPUTE_MATMUL_H
#include <stdint.h>
#include "ft_tensix_circular_buffer.h"
#include "ft_tensix_compute.h"
#include "../fw/ft_bh_isa.h"
/* The SFPI compiler's replay-record intrinsic. Its usual declaration cannot be included from C,
* so it is declared here (ft_tensix_compute_reduce.h declares the same prototype). With
* record = 1 the next `length` Tensix instructions of this thread are stored into replay slots
* [start, start + length) instead of executed. */
void __builtin_rvtt_ttreplay(volatile void *instruction_buffer, unsigned length, unsigned unused0,
unsigned unused1, unsigned start, unsigned execute_while_loading,
unsigned record);
#define FT_TENSIX_REPLAY_RECORD(start, length) \
__builtin_rvtt_ttreplay((volatile void *)__instrn_buffer, (length), 0, 0, (start), 0, 1)
/* REPLAY word that plays slots [start, start + length) (a data value for the MOP). */
#define FT_TENSIX_REPLAY_INSN(start, length) FT_BH_ENC_REPLAY((start), (length), 0, 0)
/* Replay layout (Foundry convention). */
#define FT_TENSIX_MATH_REPLAY_BUF_OFFSET 16u
#define FT_TENSIX_MATH_MATMUL_REPLAY_LEN 16u
#define FT_TENSIX_MATH_MATMUL_HALF_REPLAY_LEN 8u
#define FT_TENSIX_UNPACK_MATMUL_REPLAY_PROG_LEN 12u
#define FT_TENSIX_UNPACK_MATMUL_REPLAY_RUN_LEN 6u
/* Unpack-thread GPRs (Foundry convention). */
#ifndef FT_TENSIX_GPR_UNPACK_TMP0
#define FT_TENSIX_GPR_UNPACK_TMP0 12u
#endif
#ifndef FT_TENSIX_GPR_UNPACK_KT_DIM
#define FT_TENSIX_GPR_UNPACK_KT_DIM 38u
#endif
/* ===== Math thread ======================================================================= */
#ifdef FT_TRISC_MATH
/** Address modifiers of the full-tile walk. `transpose` swaps the SrcA steps of slots 1, 4. */
static FT_BH_INLINE void ft_tensix_math_matmul_configure_addrmod(uint32_t transpose,
uint32_t fidelity_increment)
{
FT_TENSIX_ADDR_MOD_SET(FT_BH_ADDR_MOD_0, FT_TENSIX_ADDR_MOD_SRC_VAL(0, 0, 0),
FT_TENSIX_ADDR_MOD_SRC_VAL(8, 0, 0),
FT_TENSIX_ADDR_MOD_DEST_VAL(8, 0, 0, 0),
FT_TENSIX_ADDR_MOD_FIDELITY_VAL(0, 0),
FT_TENSIX_ADDR_MOD_BIAS_VAL(0, 0));
FT_TENSIX_ADDR_MOD_SET(FT_BH_ADDR_MOD_5, FT_TENSIX_ADDR_MOD_SRC_VAL(0, 1, 1),
FT_TENSIX_ADDR_MOD_SRC_VAL(0, 1, 1),
FT_TENSIX_ADDR_MOD_DEST_VAL(0, 1, 1, 0),
FT_TENSIX_ADDR_MOD_FIDELITY_VAL(fidelity_increment, 0),
FT_TENSIX_ADDR_MOD_BIAS_VAL(0, 0));
if (transpose != 0) {
FT_TENSIX_ADDR_MOD_SET(FT_BH_ADDR_MOD_1, FT_TENSIX_ADDR_MOD_SRC_VAL(32, 0, 0),
FT_TENSIX_ADDR_MOD_SRC_VAL(0, 0, 1),
FT_TENSIX_ADDR_MOD_DEST_VAL(8, 0, 0, 0),
FT_TENSIX_ADDR_MOD_FIDELITY_VAL(0, 0),
FT_TENSIX_ADDR_MOD_BIAS_VAL(0, 0));
} else {
FT_TENSIX_ADDR_MOD_SET(FT_BH_ADDR_MOD_1, FT_TENSIX_ADDR_MOD_SRC_VAL(16, 0, 0),
FT_TENSIX_ADDR_MOD_SRC_VAL(0, 0, 1),
FT_TENSIX_ADDR_MOD_DEST_VAL(8, 0, 0, 0),
FT_TENSIX_ADDR_MOD_FIDELITY_VAL(0, 0),
FT_TENSIX_ADDR_MOD_BIAS_VAL(0, 0));
}
FT_TENSIX_ADDR_MOD_SET(FT_BH_ADDR_MOD_2, FT_TENSIX_ADDR_MOD_SRC_VAL(0, 0, 1),
FT_TENSIX_ADDR_MOD_SRC_VAL(32, 0, 1),
FT_TENSIX_ADDR_MOD_DEST_VAL(8, 0, 0, 0),
FT_TENSIX_ADDR_MOD_FIDELITY_VAL(0, 0),
FT_TENSIX_ADDR_MOD_BIAS_VAL(0, 0));
if (transpose != 0) {
FT_TENSIX_ADDR_MOD_SET(FT_BH_ADDR_MOD_4, FT_TENSIX_ADDR_MOD_SRC_VAL(16, 0, 1),
FT_TENSIX_ADDR_MOD_SRC_VAL(48, 0, 1),
FT_TENSIX_ADDR_MOD_DEST_VAL(0, 0, 1, 0),
FT_TENSIX_ADDR_MOD_FIDELITY_VAL(0, 0),
FT_TENSIX_ADDR_MOD_BIAS_VAL(0, 0));
} else {
FT_TENSIX_ADDR_MOD_SET(FT_BH_ADDR_MOD_4, FT_TENSIX_ADDR_MOD_SRC_VAL(32, 0, 1),
FT_TENSIX_ADDR_MOD_SRC_VAL(48, 0, 1),
FT_TENSIX_ADDR_MOD_DEST_VAL(0, 0, 1, 0),
FT_TENSIX_ADDR_MOD_FIDELITY_VAL(0, 0),
FT_TENSIX_ADDR_MOD_BIAS_VAL(0, 0));
}
}
/** Record the 16 MVMULs of one fidelity phase and program a MOP that replays them
* `inner_loops` times (once per fidelity phase at high fidelity). At low fidelity the last
* MVMUL releases SrcA; at high fidelity the MOP end op does, after all phases. */
static FT_BH_INLINE void ft_tensix_math_matmul_configure_mop(uint32_t inner_loops,
int high_fidelity)
{
ft_tensix_mop_template t;
FT_TENSIX_REPLAY_RECORD(FT_TENSIX_MATH_REPLAY_BUF_OFFSET, FT_TENSIX_MATH_MATMUL_REPLAY_LEN);
FT_BH_TTINSN_MVMUL(FT_BH_SETRWC_CLR_NONE, 0, FT_BH_ADDR_MOD_0, 0);
FT_BH_TTINSN_MVMUL(FT_BH_SETRWC_CLR_NONE, 0, FT_BH_ADDR_MOD_1, 0);
FT_BH_TTINSN_MVMUL(FT_BH_SETRWC_CLR_NONE, 0, FT_BH_ADDR_MOD_0, 0);
FT_BH_TTINSN_MVMUL(FT_BH_SETRWC_CLR_NONE, 0, FT_BH_ADDR_MOD_2, 0);
FT_BH_TTINSN_MVMUL(FT_BH_SETRWC_CLR_NONE, 0, FT_BH_ADDR_MOD_0, 0);
FT_BH_TTINSN_MVMUL(FT_BH_SETRWC_CLR_NONE, 0, FT_BH_ADDR_MOD_1, 0);
FT_BH_TTINSN_MVMUL(FT_BH_SETRWC_CLR_NONE, 0, FT_BH_ADDR_MOD_0, 0);
FT_BH_TTINSN_MVMUL(FT_BH_SETRWC_CLR_NONE, 0, FT_BH_ADDR_MOD_4, 0);
FT_BH_TTINSN_MVMUL(FT_BH_SETRWC_CLR_NONE, 0, FT_BH_ADDR_MOD_0, 0);
FT_BH_TTINSN_MVMUL(FT_BH_SETRWC_CLR_NONE, 0, FT_BH_ADDR_MOD_1, 0);
FT_BH_TTINSN_MVMUL(FT_BH_SETRWC_CLR_NONE, 0, FT_BH_ADDR_MOD_0, 0);
FT_BH_TTINSN_MVMUL(FT_BH_SETRWC_CLR_NONE, 0, FT_BH_ADDR_MOD_2, 0);
FT_BH_TTINSN_MVMUL(FT_BH_SETRWC_CLR_NONE, 0, FT_BH_ADDR_MOD_0, 0);
FT_BH_TTINSN_MVMUL(FT_BH_SETRWC_CLR_NONE, 0, FT_BH_ADDR_MOD_1, 0);
FT_BH_TTINSN_MVMUL(FT_BH_SETRWC_CLR_NONE, 0, FT_BH_ADDR_MOD_0, 0);
if (high_fidelity) {
FT_BH_TTINSN_MVMUL(FT_BH_SETRWC_CLR_NONE, 0, FT_BH_ADDR_MOD_5, 0);
} else {
FT_BH_TTINSN_MVMUL(FT_BH_SETRWC_CLR_A, 0, FT_BH_ADDR_MOD_5, 0);
}
t = ft_tensix_mop_template_1(1u, inner_loops,
FT_TENSIX_REPLAY_INSN(FT_TENSIX_MATH_REPLAY_BUF_OFFSET,
FT_TENSIX_MATH_MATMUL_REPLAY_LEN));
if (high_fidelity) {
t.end_op0 = FT_BH_ENC_SETRWC(FT_BH_SETRWC_CLR_A, 0, 0, 0, 0, FT_BH_SETRWC_SET_ABD_F);
t.end_op1 = FT_BH_ENC_NOP;
}
ft_tensix_mop_template_program(&t);
}
static FT_BH_INLINE void ft_tensix_math_matmul_init(uint32_t transpose,
uint32_t fidelity_increment,
uint32_t inner_loops, int high_fidelity)
{
ft_tensix_math_matmul_configure_addrmod(transpose, fidelity_increment);
ft_tensix_math_matmul_configure_mop(inner_loops, high_fidelity);
FT_BH_TTINSN_SETRWC(FT_BH_SETRWC_CLR_NONE, 0, 0, 0, 0, FT_BH_SETRWC_SET_ABD_F);
}
/** Accumulate SrcB x SrcA into Dst tile `dst_index` (Dst is not cleared here). */
static FT_BH_INLINE void ft_tensix_math_matmul(uint32_t dst_index)
{
uint32_t dst_offset = (dst_index << 6) + ((ft_tensix_dest_offset_id != 0)
? FT_TENSIX_DEST_REGISTER_HALF_SIZE
: 0u);
FT_BH_PUSH_SETC16(FT_BH_CFG_MATH_DEST_BASE_OFFSET_WORD, dst_offset);
ft_tensix_mop_template_run();
FT_BH_TTINSN_SETRWC(FT_BH_SETRWC_CLR_B, 0, 0, 0, 0, FT_BH_SETRWC_SET_ABD_F);
}
/** One row of `ct_dim` output tiles from Dst tile `dst_index` on, then release SrcB. */
static FT_BH_INLINE void ft_tensix_math_matmul_block(uint32_t dst_index, uint32_t ct_dim)
{
uint32_t column;
for (column = 0u; column < ct_dim; column++) {
uint32_t dst_offset = ((dst_index + column) << 6) +
((ft_tensix_dest_offset_id != 0) ? FT_TENSIX_DEST_REGISTER_HALF_SIZE
: 0u);
FT_BH_PUSH_SETC16(FT_BH_CFG_MATH_DEST_BASE_OFFSET_WORD, dst_offset);
ft_tensix_mop_template_run();
}
FT_BH_TTINSN_SETRWC(FT_BH_SETRWC_CLR_B, 0, 0, 0, 0, FT_BH_SETRWC_SET_ABD_F);
}
/** Address modifiers of the 16-row in0 walk. */
static FT_BH_INLINE void ft_tensix_math_matmul_configure_addrmod_in0_16row(
uint32_t fidelity_increment)
{
FT_TENSIX_ADDR_MOD_SET(FT_BH_ADDR_MOD_0, FT_TENSIX_ADDR_MOD_SRC_VAL(0, 0, 0),
FT_TENSIX_ADDR_MOD_SRC_VAL(8, 0, 0),
FT_TENSIX_ADDR_MOD_DEST_VAL(8, 0, 0, 0),
FT_TENSIX_ADDR_MOD_FIDELITY_VAL(0, 0),
FT_TENSIX_ADDR_MOD_BIAS_VAL(0, 0));
FT_TENSIX_ADDR_MOD_SET(FT_BH_ADDR_MOD_5, FT_TENSIX_ADDR_MOD_SRC_VAL(0, 1, 1),
FT_TENSIX_ADDR_MOD_SRC_VAL(0, 1, 1),
FT_TENSIX_ADDR_MOD_DEST_VAL(0, 1, 1, 0),
FT_TENSIX_ADDR_MOD_FIDELITY_VAL(fidelity_increment, 0),
FT_TENSIX_ADDR_MOD_BIAS_VAL(0, 0));
FT_TENSIX_ADDR_MOD_SET(FT_BH_ADDR_MOD_1, FT_TENSIX_ADDR_MOD_SRC_VAL(16, 0, 0),
FT_TENSIX_ADDR_MOD_SRC_VAL(0, 0, 1),
FT_TENSIX_ADDR_MOD_DEST_VAL(8, 0, 0, 0),
FT_TENSIX_ADDR_MOD_FIDELITY_VAL(0, 0),
FT_TENSIX_ADDR_MOD_BIAS_VAL(0, 0));
FT_TENSIX_ADDR_MOD_SET(FT_BH_ADDR_MOD_2, FT_TENSIX_ADDR_MOD_SRC_VAL(16, 0, 0),
FT_TENSIX_ADDR_MOD_SRC_VAL(0, 0, 1),
FT_TENSIX_ADDR_MOD_DEST_VAL(8, 0, 0, 0),
FT_TENSIX_ADDR_MOD_FIDELITY_VAL(0, 0),
FT_TENSIX_ADDR_MOD_BIAS_VAL(0, 0));
FT_TENSIX_ADDR_MOD_SET(FT_BH_ADDR_MOD_4, FT_TENSIX_ADDR_MOD_SRC_VAL(16, 0, 0),
FT_TENSIX_ADDR_MOD_SRC_VAL(16, 0, 1),
FT_TENSIX_ADDR_MOD_DEST_VAL(0, 0, 1, 0),
FT_TENSIX_ADDR_MOD_FIDELITY_VAL(0, 0),
FT_TENSIX_ADDR_MOD_BIAS_VAL(0, 0));
}
/** As ft_tensix_math_matmul_configure_mop with 8 MVMULs per phase. */
static FT_BH_INLINE void ft_tensix_math_matmul_configure_mop_in0_16row(uint32_t inner_loops,
int high_fidelity)
{
ft_tensix_mop_template t;
FT_TENSIX_REPLAY_RECORD(FT_TENSIX_MATH_REPLAY_BUF_OFFSET,
FT_TENSIX_MATH_MATMUL_HALF_REPLAY_LEN);
FT_BH_TTINSN_MVMUL(FT_BH_SETRWC_CLR_NONE, 0, FT_BH_ADDR_MOD_0, 0);
FT_BH_TTINSN_MVMUL(FT_BH_SETRWC_CLR_NONE, 0, FT_BH_ADDR_MOD_2, 0);
FT_BH_TTINSN_MVMUL(FT_BH_SETRWC_CLR_NONE, 0, FT_BH_ADDR_MOD_0, 0);
FT_BH_TTINSN_MVMUL(FT_BH_SETRWC_CLR_NONE, 0, FT_BH_ADDR_MOD_4, 0);
FT_BH_TTINSN_MVMUL(FT_BH_SETRWC_CLR_NONE, 0, FT_BH_ADDR_MOD_0, 0);
FT_BH_TTINSN_MVMUL(FT_BH_SETRWC_CLR_NONE, 0, FT_BH_ADDR_MOD_1, 0);
FT_BH_TTINSN_MVMUL(FT_BH_SETRWC_CLR_NONE, 0, FT_BH_ADDR_MOD_0, 0);
if (high_fidelity) {
FT_BH_TTINSN_MVMUL(FT_BH_SETRWC_CLR_NONE, 0, FT_BH_ADDR_MOD_5, 0);
} else {
FT_BH_TTINSN_MVMUL(FT_BH_SETRWC_CLR_A, 0, FT_BH_ADDR_MOD_5, 0);
}
t = ft_tensix_mop_template_1(1u, inner_loops,
FT_TENSIX_REPLAY_INSN(FT_TENSIX_MATH_REPLAY_BUF_OFFSET,
FT_TENSIX_MATH_MATMUL_HALF_REPLAY_LEN));
if (high_fidelity) {
t.end_op0 = FT_BH_ENC_SETRWC(FT_BH_SETRWC_CLR_A, 0, 0, 0, 0, FT_BH_SETRWC_SET_ABD_F);
t.end_op1 = FT_BH_ENC_NOP;
}
ft_tensix_mop_template_program(&t);
}
static FT_BH_INLINE void ft_tensix_math_matmul_init_in0_16row(uint32_t fidelity_increment,
uint32_t inner_loops,
int high_fidelity)
{
ft_tensix_math_matmul_configure_addrmod_in0_16row(fidelity_increment);
ft_tensix_math_matmul_configure_mop_in0_16row(inner_loops, high_fidelity);
FT_BH_TTINSN_SETRWC(FT_BH_SETRWC_CLR_NONE, 0, 0, 0, 0, FT_BH_SETRWC_SET_ABD_F);
}
#endif /* FT_TRISC_MATH */
/* ===== Unpack thread ===================================================================== */
#ifdef FT_TRISC_UNPACK
/** Record the two-context unpack program and program the single-loop unpack MOP to replay
* the half of the current context (MOPExpander.md, unpack template registers 1..8). */
static FT_BH_INLINE void ft_tensix_unpack_ab_matmul_mop_config(void)
{
volatile uint32_t *mop_cfg = FT_TENSIX_MOP_CFG;
FT_TENSIX_REPLAY_RECORD(0u, FT_TENSIX_UNPACK_MATMUL_REPLAY_PROG_LEN);
/* Context 0: unpack SrcA, then unpacker 0 base address += A tile size. */
FT_BH_TTINSN_UNPACR(FT_BH_UNPACR_SRC_A, 0, 0, 0, 0, 1, 1, FT_BH_UNPACR_RAREFYB_DISABLE, 0, 0,
0, 0, 1);
FT_BH_TTINSN_RDCFG(FT_TENSIX_GPR_UNPACK_TMP0, FT_BH_CFG_UNPACKER0_L1_BASE_CONTEXT0_WORD);
FT_BH_TTINSN_ADDDMAREG(0, FT_TENSIX_GPR_UNPACK_TMP0, FT_TENSIX_GPR_UNPACK_TMP0,
FT_TENSIX_GPR_UNPACK_TILE_SIZE_A);
FT_BH_TTINSN_STALLWAIT(FT_BH_STALLWAIT_BLOCK_CFG, FT_BH_STALLWAIT_COND_THCON);
FT_BH_TTINSN_WRCFG(FT_TENSIX_GPR_UNPACK_TMP0, FT_BH_WRCFG_32B,
FT_BH_CFG_UNPACKER0_L1_BASE_CONTEXT0_WORD);
FT_BH_TTINSN_NOP;
/* Context 1: the same on the context-1 base address. */
FT_BH_TTINSN_UNPACR(FT_BH_UNPACR_SRC_A, 0, 0, 0, 0, 1, 1, FT_BH_UNPACR_RAREFYB_DISABLE, 0, 0,
0, 0, 1);
FT_BH_TTINSN_RDCFG(FT_TENSIX_GPR_UNPACK_TMP0, FT_BH_CFG_UNPACKER0_L1_BASE_CONTEXT1_WORD);
FT_BH_TTINSN_ADDDMAREG(0, FT_TENSIX_GPR_UNPACK_TMP0, FT_TENSIX_GPR_UNPACK_TMP0,
FT_TENSIX_GPR_UNPACK_TILE_SIZE_A);
FT_BH_TTINSN_STALLWAIT(FT_BH_STALLWAIT_BLOCK_CFG, FT_BH_STALLWAIT_COND_THCON);
FT_BH_TTINSN_WRCFG(FT_TENSIX_GPR_UNPACK_TMP0, FT_BH_WRCFG_32B,
FT_BH_CFG_UNPACKER0_L1_BASE_CONTEXT1_WORD);
FT_BH_TTINSN_NOP;
ft_tensix_mop_sync();
/* Unpack template: [1] flags, [2] B instruction, [3] A instruction, [4..6] A1..A3,
* [7] skip-A instruction (zmask set: context 1), [8] skip-B instruction. */
mop_cfg[1] = 0u;
mop_cfg[2] = 0u;
mop_cfg[3] = FT_TENSIX_REPLAY_INSN(0u, FT_TENSIX_UNPACK_MATMUL_REPLAY_RUN_LEN);
mop_cfg[4] = 0u;
mop_cfg[5] = 0u;
mop_cfg[6] = 0u;
mop_cfg[7] = FT_TENSIX_REPLAY_INSN(FT_TENSIX_UNPACK_MATMUL_REPLAY_RUN_LEN,
FT_TENSIX_UNPACK_MATMUL_REPLAY_RUN_LEN);
mop_cfg[8] = 0u;
}
/** Configure the matmul unpack: in-face transpose of SrcA, row lengths of both unpackers,
* K tile count (GPR 38). */
static FT_BH_INLINE void ft_tensix_unpack_ab_matmul_init(uint32_t transpose, uint32_t unpa_x_end,
uint32_t unpb_x_end, uint32_t kt_dim)
{
FT_TENSIX_CFG_RMW_FIELD(UNPACKER0_HALOIZE_MODE, transpose);
FT_BH_TTINSN_SETADCZW(FT_BH_SETADC_UNP_AB, 0, 0, 0, 0, 0xF);
FT_BH_PUSH_SETADCXX(FT_BH_SETADC_UNP_A, unpa_x_end, 0x0);
FT_BH_PUSH_SETADCXX(FT_BH_SETADC_UNP_B, unpb_x_end, 0x0);
FT_BH_PUSH_SETDMAREG(0, FT_TENSIX_LOWER_HALFWORD(kt_dim), 0,
FT_TENSIX_LO_16(FT_TENSIX_GPR_UNPACK_KT_DIM));
ft_tensix_unpack_ab_matmul_mop_config();
}
/** Set the SrcA step between K tiles (GPR 36, low half). */
static FT_BH_INLINE void ft_tensix_unpack_matmul_set_srca_tile_stride(uint32_t tile_stride)
{
FT_BH_PUSH_SETDMAREG(0, FT_TENSIX_LOWER_HALFWORD(tile_stride), 0,
FT_TENSIX_LO_16(FT_TENSIX_GPR_UNPACK_TILE_SIZE_A));
}
/** Unpack in0 tile `tile_index_a` of CB `operand_a` to SrcB and `ct_dim` in1 tiles from
* `tile_index_b` of CB `operand_b` to SrcA, then flip the config context. */
static FT_BH_INLINE void ft_tensix_unpack_ab_matmul(uint32_t operand_a, uint32_t operand_b,
uint32_t tile_index_a, uint32_t tile_index_b,
uint32_t ct_dim)
{
uint32_t base_address_a = ft_tensix_cb(operand_a)->fifo_read_pointer - 1u;
uint32_t base_address_b = ft_tensix_cb(operand_b)->fifo_read_pointer - 1u;
uint32_t tile_size_a = ft_tensix_cb(operand_a)->fifo_page_size;
uint32_t tile_size_b = ft_tensix_cb(operand_b)->fifo_page_size;
volatile uint32_t FT_BH_REG_PTR *cfg = ft_tensix_cfg_pointer();
uint32_t address_a = base_address_a + tile_size_a * tile_index_a;
uint32_t address_b = base_address_b + tile_size_b * tile_index_b;
uint32_t context;
/* Wait for a free config context (two exist). */
while (ft_tensix_semaphore_read(FT_TENSIX_SEM_UNPACK_SYNC) >= 2u) {
}
context = unp_cfg_context;
if (context != 0) {
cfg[FT_BH_CFG_UNPACKER0_L1_BASE_CONTEXT1_WORD] = address_b;
cfg[FT_BH_CFG_UNPACKER1_L1_BASE_CONTEXT1_WORD] = address_a;
} else {
cfg[FT_BH_CFG_UNPACKER0_L1_BASE_CONTEXT0_WORD] = address_b;
cfg[FT_BH_CFG_UNPACKER1_L1_BASE_CONTEXT0_WORD] = address_a;
}
ft_tensix_semaphore_post(FT_TENSIX_SEM_UNPACK_SYNC);
FT_BH_TTINSN_STALLWAIT(FT_BH_STALLWAIT_BLOCK_UNPACK, FT_BH_STALLWAIT_COND_TRISC_CFG);
FT_BH_TTINSN_UNPACR(FT_BH_UNPACR_SRC_B, 0, 0, 0, 0, 1, 1, FT_BH_UNPACR_RAREFYB_DISABLE, 0, 0,
0, 0, 1);
FT_BH_PUSH_MOP(0, ct_dim - 1u, (context == 0) ? 0u : 0xffu);
FT_BH_TTINSN_SEMGET(FT_TENSIX_T6_SEM(FT_TENSIX_SEM_UNPACK_SYNC));
unp_cfg_context = 1u - context;
if (context != 0) {
FT_BH_TTINSN_SETC16(FT_BH_CFG_UNPACKER0_CONTEXT_OFFSET_WORD, 0x0000);
} else {
FT_BH_TTINSN_SETC16(FT_BH_CFG_UNPACKER0_CONTEXT_OFFSET_WORD, 0x0101);
}
}
#endif /* FT_TRISC_UNPACK */
#endif /* FT_TENSIX_COMPUTE_MATMUL_H */