Foundry/tt/tests/ft_tt_blackhole_doc_layout.h

239 lines
8.1 KiB
C

/* SPDX-License-Identifier: AGPL-3.0-or-later */
/**
* @file ft_tt_blackhole_doc_layout.h
* @brief The Blackhole NoC layout as the public tt-isa-documentation states it, written
* out independently of ft_tt_arch_blackhole.c so the coordinate tests compare two
* separate readings of the docs.
*
* Sources (paths relative to the tt-isa-documentation root):
* [COORD] BlackholeA0/NoC/Coordinates.md — translated coordinate table and the
* harvested-tile placement rules
* [LUA] Diagrams/Src/NoC.lua — TileLabel_BH (what sits at each NoC #0 node),
* NocSize_Arch.bh, and the bh_y211 / bh_y1223 / bh_y25 / bh_x8 examples
* Values with no public page are the numbers given in the clean-room spec and say so.
*
* Header-only, every helper `static inline` so a test that uses part of it builds
* warning-free.
*
* @status Used by tests/test_coord.c and tests/test_harvesting.c.
* @issues None
* @todo None
*/
#ifndef FT_TT_BLACKHOLE_DOC_LAYOUT_H
#define FT_TT_BLACKHOLE_DOC_LAYOUT_H
#include <stdbool.h>
#include <stdint.h>
#include "ft_tt_coord.h"
/* [LUA] NocSize_Arch.bh = { w = 17, h = 12 }. */
#define BH_DOC_NOC_WIDTH 17u
#define BH_DOC_NOC_HEIGHT 12u
/* [COORD] Tensix at x 1-7 and 10-16, y 2-11: 14 columns x 10 rows. */
#define BH_DOC_TENSIX_COLUMNS 14u
#define BH_DOC_TENSIX_ROWS 10u
#define BH_DOC_FIRST_TENSIX_ROW 2u
#define BH_DOC_ALL_COLUMNS_MASK 0x3FFFu
/* [COORD] eight 4 GiB banks, "same 4 GiB exposed on each" of 3 tiles. */
#define BH_DOC_DRAM_BANKS 8u
#define BH_DOC_DRAM_PORTS_PER_BANK 3u
#define BH_DOC_ALL_BANKS_MASK 0xFFu
#define BH_DOC_DRAM_ALIAS_FIRST_X 17u
#define BH_DOC_DRAM_ALIAS_FIRST_Y 12u
#define BH_DOC_DRAM_ALIAS_LAST_Y 23u
/* [LUA] TileLabel_BH row y = 1 names E0..E13. */
#define BH_DOC_ETH_CHANNELS 14u
#define BH_DOC_ALL_CHANNELS_MASK 0x3FFFu
#define BH_DOC_ETH_ALIAS_FIRST_X 20u
#define BH_DOC_ETH_ALIAS_LAST_X 31u
#define BH_DOC_ETH_ALIAS_Y 25u
/* [LUA] x = 8: CPU clusters at y 3, 5, 7, 9. */
#define BH_DOC_L2CPU_TILES 4u
#define BH_DOC_ALL_L2CPU_MASK 0xFu
#define BH_DOC_FIXED_COLUMN_X 8u
/* [COORD] "19, 24: PCI Express tile (whichever one is connected to the host)". */
#define BH_DOC_PCIE_ALIAS_X 19u
#define BH_DOC_PCIE_ALIAS_Y 24u
/** NoC #0 x of Tensix grid column `column` (columns counted west to east). */
static inline uint32_t bh_doc_tensix_noc0_x(uint32_t column)
{
return column < 7u ? column + 1u : column + 3u;
}
/** Grid column at NoC #0 x, or BH_DOC_TENSIX_COLUMNS when x holds no Tensix. */
static inline uint32_t bh_doc_tensix_column_at_x(uint32_t x)
{
if (x >= 1u && x <= 7u)
return x - 1u;
if (x >= 10u && x <= 16u)
return x - 3u;
return BH_DOC_TENSIX_COLUMNS;
}
/** Spec-given (no public page): telemetry bit reporting grid column `column`. */
static inline uint32_t bh_doc_tensix_telemetry_bit(uint32_t column)
{
static const uint8_t bit_by_column[BH_DOC_TENSIX_COLUMNS] = { 0, 2, 4, 6, 8, 10, 12,
13, 11, 9, 7, 5, 3, 1 };
return bit_by_column[column];
}
/** ARC's enabled-columns word for a part whose `harvested_columns` (grid-column bits) are
* fused off. */
static inline uint32_t bh_doc_enabled_column_word(uint32_t harvested_columns)
{
uint32_t word = 0u;
uint32_t column;
for (column = 0; column < BH_DOC_TENSIX_COLUMNS; column++) {
if (!(harvested_columns & (1u << column)))
word |= 1u << bh_doc_tensix_telemetry_bit(column);
}
return word;
}
/**
* Translated x of the Tensix column at NoC #0 x `noc0_x`, following [LUA] bh_y211 and the
* [COORD] rule: surviving columns take translated x 1, 2, ... in NoC #0 order, x = 8 and
* x = 9 are never handed out, and fused columns take the remaining (maximal) values.
*/
static inline uint32_t bh_doc_tensix_translated_x(uint32_t noc0_x, uint32_t harvested_columns)
{
uint32_t translated_by_noc0_x[BH_DOC_NOC_WIDTH] = { 0 };
uint32_t next = 1u;
uint32_t pass;
uint32_t x;
for (pass = 0; pass < 2u; pass++) {
for (x = 1u; x < BH_DOC_NOC_WIDTH; x++) {
uint32_t column = bh_doc_tensix_column_at_x(x);
bool fused;
if (column == BH_DOC_TENSIX_COLUMNS || translated_by_noc0_x[x] != 0u)
continue;
fused = (harvested_columns & (1u << column)) != 0u;
if (fused != (pass == 1u))
continue;
translated_by_noc0_x[x] = next++;
if (next == 8u)
next = 10u;
}
}
return translated_by_noc0_x[noc0_x];
}
/** Bank whose tile sits at NoC #0 (x, y) for x = 0 or 9 ([LUA] TileLabel_BH "D" labels). */
static inline uint32_t bh_doc_dram_bank_at(uint32_t x, uint32_t y)
{
static const uint8_t bank_by_y[BH_DOC_NOC_HEIGHT] = { 0, 0, 1, 1, 2, 3, 3, 3, 2, 2, 1, 0 };
return bank_by_y[y] + (x == 9u ? 4u : 0u);
}
/** [LUA] bh_y1223 (p100, D2 fused): translated y given to the DRAM tile at NoC #0 row y. */
static inline uint32_t bh_doc_dram_example_translated_y(uint32_t noc0_y)
{
static const uint8_t translated_by_y[BH_DOC_NOC_HEIGHT] = { 12, 13, 15, 17, 22, 18,
20, 19, 23, 21, 16, 14 };
return translated_by_y[noc0_y];
}
/**
* NoC #0 row of port `port` of `bank`. Port order within a bank is the order of the
* translated y the doc's bh_y1223 example gives that bank's tiles, so port p is the tile
* at bank-relative translated offset p.
*/
static inline uint32_t bh_doc_dram_port_noc0_y(uint32_t bank, uint32_t port)
{
uint32_t column_x = bank < 4u ? 0u : 9u;
uint32_t y;
for (y = 0; y < BH_DOC_NOC_HEIGHT; y++) {
uint32_t rank = 0u;
uint32_t other;
if (bh_doc_dram_bank_at(column_x, y) != bank)
continue;
for (other = 0; other < BH_DOC_NOC_HEIGHT; other++) {
if (bh_doc_dram_bank_at(column_x, other) == bank &&
bh_doc_dram_example_translated_y(other) < bh_doc_dram_example_translated_y(y))
rank++;
}
if (rank == port)
return y;
}
return BH_DOC_NOC_HEIGHT;
}
/** NoC #0 x of the bank's DRAM column. */
static inline uint32_t bh_doc_dram_noc0_x(uint32_t bank)
{
return bank < 4u ? 0u : 9u;
}
/** Ethernet channel at NoC #0 (x, 1) per [LUA] TileLabel_BH, or BH_DOC_ETH_CHANNELS. */
static inline uint32_t bh_doc_eth_channel_at_x(uint32_t x)
{
static const uint8_t channel_by_x[BH_DOC_NOC_WIDTH] = { 14, 0, 2, 4, 6, 8, 10, 12, 14,
14, 13, 11, 9, 7, 5, 3, 1 };
return x < BH_DOC_NOC_WIDTH ? channel_by_x[x] : BH_DOC_ETH_CHANNELS;
}
/** NoC #0 x of Ethernet channel `channel`. */
static inline uint32_t bh_doc_eth_noc0_x(uint32_t channel)
{
uint32_t x;
for (x = 0; x < BH_DOC_NOC_WIDTH; x++) {
if (bh_doc_eth_channel_at_x(x) == channel)
return x;
}
return BH_DOC_NOC_WIDTH;
}
/** NoC #0 y of L2CPU tile `tile` (tiles ordered by y). */
static inline uint32_t bh_doc_l2cpu_noc0_y(uint32_t tile)
{
return 3u + 2u * tile;
}
/** Spec-given (no public page): telemetry bit of L2CPU tile `tile` (y = 3, 5, 7, 9). */
static inline uint32_t bh_doc_l2cpu_telemetry_bit(uint32_t tile)
{
static const uint8_t bit_by_tile[BH_DOC_L2CPU_TILES] = { 0, 2, 3, 1 };
return bit_by_tile[tile];
}
/** What sits at NoC #0 (x, y), transcribed from [LUA] TileLabel_BH. An empty label is a
* router-only node. */
static inline ft_tt_core_type bh_doc_noc0_tile_type(uint32_t x, uint32_t y)
{
if (x >= BH_DOC_NOC_WIDTH || y >= BH_DOC_NOC_HEIGHT)
return FT_TT_CORE_NONE;
if (x == 0u || x == 9u)
return FT_TT_CORE_DRAM;
if (x == BH_DOC_FIXED_COLUMN_X) {
if (y == 0u)
return FT_TT_CORE_ARC;
if (y == 2u)
return FT_TT_CORE_SECURITY;
if (y == 3u || y == 5u || y == 7u || y == 9u)
return FT_TT_CORE_L2CPU;
return FT_TT_CORE_ROUTER;
}
if (y == 1u)
return FT_TT_CORE_ETH;
if (y == 0u)
return (x == 2u || x == 11u) ? FT_TT_CORE_PCIE : FT_TT_CORE_ROUTER;
return FT_TT_CORE_TENSIX;
}
#endif /* FT_TT_BLACKHOLE_DOC_LAYOUT_H */