Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 58 additions & 37 deletions target/linx/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -2146,6 +2146,14 @@ static void linx_cpu_do_interrupt(CPUState *cs)
}
return;

case LINX_EXCP_TILE_FAULT:
linx_deliver_sync_trap(cs, env, last_pc, env->insn_pc_next,
LINX_TRAPNUM_BLOCK_TRAP,
true, /* argv: fault address/TPC */
false, /* fault */
(env->in_body != 0));
return;

case LINX_EXCP_ILLEGAL_INST:
qemu_log_mask(LOG_GUEST_ERROR,
"Linx: illegal instruction at PC=0x%" PRIx64 "\n",
Expand Down Expand Up @@ -3924,19 +3932,6 @@ static int linx_cpu_pre_save(void *opaque)
}
uint8_t expected_reserved[LINX_TILE_HAND_COUNT] = { 0 };
uint16_t expected_pin[LINX_TILE_HAND_COUNT * LINX_TILE_HAND_DEPTH] = { 0 };
const uint16_t owner = 1u << (env->acr & 0xfu);
for (unsigned i = 0; i < env->tile_iot_count; i++) {
for (unsigned source = 0; source < 2; source++) {
if ((env->tile_iot_src_valid[i] & (1u << source)) != 0) {
expected_pin[env->tile_iot_src_phys[i][source]] = owner;
}
}
if (env->tile_iot_output_valid[i]) {
const unsigned tile = env->tile_iot_output_phys[i];
expected_reserved[tile / LINX_TILE_HAND_DEPTH] |=
1u << (tile % LINX_TILE_HAND_DEPTH);
}
}
if (memcmp(expected_reserved, env->tile_hand_reserved,
sizeof(expected_reserved)) != 0 ||
memcmp(expected_pin, env->tile_pin_owner,
Expand All @@ -3951,6 +3946,11 @@ static bool linx_cpu_post_load(void *opaque, int version_id, Error **errp)
LinxCPU *cpu = opaque;
CPULinxState *env = &cpu->env;

if (version_id >= 12 && version_id < 16) {
memcpy(env->tile_reg_capacity, env->tile_reg_bytes,
sizeof(env->tile_reg_capacity));
}

if (version_id < 12) {
/* v11 carried no tile backing or allocator state. */
env->tile_func = 0;
Expand Down Expand Up @@ -3992,6 +3992,7 @@ static bool linx_cpu_post_load(void *opaque, int version_id, Error **errp)
env->tile_acc_src0 = 0;
env->tile_acc_src1 = 0;
memset(env->tile_reg, 0, sizeof(env->tile_reg));
memset(env->tile_reg_capacity, 0, sizeof(env->tile_reg_capacity));
memset(env->tile_reg_bytes, 0, sizeof(env->tile_reg_bytes));
memset(env->tile_reg_elem_bytes, 0, sizeof(env->tile_reg_elem_bytes));
memset(env->tile_reg_dtype, 0, sizeof(env->tile_reg_dtype));
Expand All @@ -4003,6 +4004,10 @@ static bool linx_cpu_post_load(void *opaque, int version_id, Error **errp)
memset(env->tile_reg_rows, 0, sizeof(env->tile_reg_rows));
memset(env->tile_acc, 0, sizeof(env->tile_acc));
env->tile_acc_bytes = 0;
env->tile_acc_dtype = 0;
env->tile_acc_valid = 0;
env->tile_acc_cols = 0;
env->tile_acc_rows = 0;
return true;
}

Expand Down Expand Up @@ -4059,6 +4064,18 @@ static bool linx_cpu_post_load(void *opaque, int version_id, Error **errp)
memset(env->tile_reg_cols, 0, sizeof(env->tile_reg_cols));
memset(env->tile_reg_rows, 0, sizeof(env->tile_reg_rows));
}
if (version_id < 17) {
if (env->tile_acc_bytes != 0) {
error_setg(errp,
"linx: cannot migrate nonempty pre-v17 CUBE ACC "
"without numeric type and shape metadata");
return false;
}
env->tile_acc_dtype = 0;
env->tile_acc_valid = 0;
env->tile_acc_cols = 0;
env->tile_acc_rows = 0;
}

if (env->tile_ior_count > LINX_TILE_MAX_IOR ||
env->vec_ri_count > LINX_VEC_RI_MAX ||
Expand All @@ -4077,21 +4094,32 @@ static bool linx_cpu_post_load(void *opaque, int version_id, Error **errp)
return false;
}
if (env->tile_acc_bytes > LINX_TILE_MAX_BYTES ||
(env->tile_acc_bytes & 3u) != 0) {
(env->tile_acc_bytes & 3u) != 0 || env->tile_acc_valid > 1u ||
(!env->tile_acc_valid && (env->tile_acc_bytes != 0u ||
env->tile_acc_cols != 0u ||
env->tile_acc_rows != 0u)) ||
(env->tile_acc_valid &&
((env->tile_acc_dtype != 0u && env->tile_acc_dtype != 1u &&
env->tile_acc_dtype != 16u && env->tile_acc_dtype != 24u) ||
env->tile_acc_cols == 0u || env->tile_acc_rows == 0u))) {
error_setg(errp, "linx: invalid migrated tile accumulator footprint");
return false;
}
uint64_t tile_capacity_in_use = 0;
for (unsigned tile = 0;
tile < LINX_TILE_HAND_COUNT * LINX_TILE_HAND_DEPTH; tile++) {
const uint32_t bytes = env->tile_reg_bytes[tile];
const uint32_t capacity = env->tile_reg_capacity[tile];
const uint32_t elem_bytes = env->tile_reg_elem_bytes[tile];
const uint32_t valid_cols = env->tile_reg_valid_cols[tile];
const uint32_t valid_rows = env->tile_reg_valid_rows[tile];
const uint32_t cols = env->tile_reg_cols[tile];
const uint32_t rows = env->tile_reg_rows[tile];
const unsigned hand = tile / LINX_TILE_HAND_DEPTH;
const unsigned depth = tile % LINX_TILE_HAND_DEPTH;
tile_capacity_in_use += capacity;
if (bytes > LINX_TILE_MAX_BYTES || (bytes & 3u) != 0 ||
capacity > LINX_TILE_PE_CAPACITY_BYTES ||
((env->tile_hand_live[hand] & (1u << depth)) != 0 && bytes == 0) ||
(bytes != 0 &&
(elem_bytes == 0 || valid_cols == 0 || valid_rows == 0 ||
Expand All @@ -4102,6 +4130,10 @@ static bool linx_cpu_post_load(void *opaque, int version_id, Error **errp)
return false;
}
}
if (tile_capacity_in_use > LINX_TILE_PE_CAPACITY_BYTES) {
error_setg(errp, "linx: migrated tile capacity exceeds PE limit");
return false;
}
for (unsigned hand = 0; hand < LINX_TILE_HAND_COUNT; hand++) {
uint8_t seen = 0;
if (env->tile_hand_count[hand] > LINX_TILE_HAND_DEPTH ||
Expand All @@ -4127,6 +4159,7 @@ static bool linx_cpu_post_load(void *opaque, int version_id, Error **errp)
return false;
}
}
uint32_t planned_output_seen = 0;
for (unsigned i = 0; i < LINX_TILE_MAX_IOT; i++) {
if (env->tile_iot_src_valid[i] > 3 ||
env->tile_iot_output_valid[i] > 1) {
Expand Down Expand Up @@ -4166,37 +4199,19 @@ static bool linx_cpu_post_load(void *opaque, int version_id, Error **errp)
if (env->tile_iot_output_valid[i]) {
const unsigned tile = env->tile_iot_output_phys[i];
if (tile >= LINX_TILE_HAND_COUNT * LINX_TILE_HAND_DEPTH ||
(env->tile_hand_reserved[tile / LINX_TILE_HAND_DEPTH] &
(1u << (tile % LINX_TILE_HAND_DEPTH))) == 0) {
(planned_output_seen & (1u << tile)) != 0 ||
(env->tile_hand_live[tile / LINX_TILE_HAND_DEPTH] &
(1u << (tile % LINX_TILE_HAND_DEPTH))) != 0) {
error_setg(errp,
"linx: invalid migrated tile binding %u output",
i);
return false;
}
planned_output_seen |= 1u << tile;
}
}
uint8_t expected_reserved[LINX_TILE_HAND_COUNT] = { 0 };
uint16_t expected_pin[LINX_TILE_HAND_COUNT * LINX_TILE_HAND_DEPTH] = { 0 };
const uint16_t owner = 1u << (env->acr & 0xfu);
for (unsigned i = 0; i < env->tile_iot_count; i++) {
for (unsigned source = 0; source < 2; source++) {
if ((env->tile_iot_src_valid[i] & (1u << source)) != 0) {
const unsigned tile = env->tile_iot_src_phys[i][source];
expected_pin[tile] = owner;
}
}
if (env->tile_iot_output_valid[i]) {
const unsigned tile = env->tile_iot_output_phys[i];
const unsigned hand = tile / LINX_TILE_HAND_DEPTH;
const uint8_t bit = 1u << (tile % LINX_TILE_HAND_DEPTH);
if (expected_reserved[hand] & bit) {
error_setg(errp,
"linx: duplicate migrated tile output owner");
return false;
}
expected_reserved[hand] |= bit;
}
}
if (memcmp(expected_reserved, env->tile_hand_reserved,
sizeof(expected_reserved)) != 0 ||
memcmp(expected_pin, env->tile_pin_owner,
Expand All @@ -4220,7 +4235,7 @@ static bool linx_cpu_post_load(void *opaque, int version_id, Error **errp)

static const VMStateDescription vmstate_linx_cpu = {
.name = "linx_cpu",
.version_id = 15,
.version_id = 17,
.minimum_version_id = 11,
.pre_save = linx_cpu_pre_save,
.post_load_errp = linx_cpu_post_load,
Expand Down Expand Up @@ -4305,6 +4320,8 @@ static const VMStateDescription vmstate_linx_cpu = {
VMSTATE_UINT32_2DARRAY_V(env.tile_reg, LinxCPU,
LINX_TILE_HAND_COUNT * LINX_TILE_HAND_DEPTH,
LINX_TILE_MAX_WORDS, 12),
VMSTATE_UINT32_ARRAY_V(env.tile_reg_capacity, LinxCPU,
LINX_TILE_HAND_COUNT * LINX_TILE_HAND_DEPTH, 16),
VMSTATE_UINT32_ARRAY_V(env.tile_reg_bytes, LinxCPU,
LINX_TILE_HAND_COUNT * LINX_TILE_HAND_DEPTH, 12),
VMSTATE_UINT8_ARRAY_V(env.tile_reg_elem_bytes, LinxCPU,
Expand All @@ -4322,6 +4339,10 @@ static const VMStateDescription vmstate_linx_cpu = {
VMSTATE_UINT32_ARRAY_V(env.tile_acc, LinxCPU,
LINX_TILE_MAX_WORDS, 12),
VMSTATE_UINT32_V(env.tile_acc_bytes, LinxCPU, 12),
VMSTATE_UINT8_V(env.tile_acc_dtype, LinxCPU, 17),
VMSTATE_UINT8_V(env.tile_acc_valid, LinxCPU, 17),
VMSTATE_UINT16_V(env.tile_acc_cols, LinxCPU, 17),
VMSTATE_UINT16_V(env.tile_acc_rows, LinxCPU, 17),
VMSTATE_UINT64(env.insn_pc_next, LinxCPU),
VMSTATE_UINT64_ARRAY(env.ssr, LinxCPU, LINX_SSR_COUNT),
VMSTATE_UINT64_2DARRAY(env.ssr_acr, LinxCPU, LINX_ACR_COUNT, LINX_SSR_COUNT),
Expand Down
30 changes: 29 additions & 1 deletion target/linx/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ enum {
LINX_EXCP_HW_BREAKPOINT = 8, /* Hardware breakpoint */
LINX_EXCP_HW_WATCHPOINT = 9, /* Hardware watchpoint */
LINX_EXCP_EXEC_STATE_CHECK = 10, /* ACR_ENTER target/state invalid */
LINX_EXCP_TILE_FAULT = 11, /* Precise Tile legality/allocation fault */
};

/*
Expand Down Expand Up @@ -223,7 +224,9 @@ typedef enum LinxTemplateKind {
#define LINX_EBARG_STACK_DEPTH 8u

/* Bring-up tile backing store limits (TAU). */
#define LINX_TILE_MAX_BYTES (64u * 1024u) /* must cover >=16KB bring-up */
#define LINX_TILE_CELL_BYTES 128u
#define LINX_TILE_PE_CAPACITY_BYTES (256u * 1024u)
#define LINX_TILE_MAX_BYTES (64u * 1024u)
#define LINX_TILE_MAX_WORDS (LINX_TILE_MAX_BYTES / 4u)

/*
Expand Down Expand Up @@ -301,6 +304,14 @@ typedef struct LinxAcrBlockState {
uint8_t tile_iot_src_phys[LINX_TILE_MAX_IOT][2];
uint8_t tile_iot_output_valid[LINX_TILE_MAX_IOT];
uint8_t tile_iot_output_phys[LINX_TILE_MAX_IOT];

/* CUBE ACC is implicit architectural state and follows its ACR. */
uint32_t tile_acc[LINX_TILE_MAX_WORDS];
uint32_t tile_acc_bytes;
uint8_t tile_acc_dtype;
uint8_t tile_acc_valid;
uint16_t tile_acc_cols;
uint16_t tile_acc_rows;
} LinxAcrBlockState;

typedef struct LinxCosimRange {
Expand Down Expand Up @@ -442,6 +453,7 @@ typedef struct CPUArchState {

/* Emulated tile backing store: 4 hands x 8 depth = 32 tiles. */
uint32_t tile_reg[32][LINX_TILE_MAX_WORDS];
uint32_t tile_reg_capacity[32]; /* architectural allocation capacity */
uint32_t tile_reg_bytes[32]; /* per-tile footprint in bytes */
uint8_t tile_reg_elem_bytes[32]; /* producer element width for sparse offsets */
uint8_t tile_reg_dtype[32]; /* canonical v0.57 producer DataType */
Expand All @@ -453,6 +465,10 @@ typedef struct CPUArchState {
/* Accumulator backing store (separate scratch). */
uint32_t tile_acc[LINX_TILE_MAX_WORDS];
uint32_t tile_acc_bytes;
uint8_t tile_acc_dtype;
uint8_t tile_acc_valid;
uint16_t tile_acc_cols;
uint16_t tile_acc_rows;

/* Current block start marker address (BPC) for trap reporting. */
uint64_t bpc;
Expand Down Expand Up @@ -837,6 +853,12 @@ static inline void linx_acr_save_block_state(CPULinxState *env, uint32_t acr)
s->tile_iot_output_valid[i] = env->tile_iot_output_valid[i];
s->tile_iot_output_phys[i] = env->tile_iot_output_phys[i];
}
memcpy(s->tile_acc, env->tile_acc, sizeof(s->tile_acc));
s->tile_acc_bytes = env->tile_acc_bytes;
s->tile_acc_dtype = env->tile_acc_dtype;
s->tile_acc_valid = env->tile_acc_valid;
s->tile_acc_cols = env->tile_acc_cols;
s->tile_acc_rows = env->tile_acc_rows;
}

static inline void linx_acr_reset_block_state_for_header(CPULinxState *env,
Expand Down Expand Up @@ -956,6 +978,12 @@ static inline void linx_acr_restore_block_state(CPULinxState *env, uint32_t acr)
env->tile_iot_output_valid[i] = s->tile_iot_output_valid[i];
env->tile_iot_output_phys[i] = s->tile_iot_output_phys[i];
}
memcpy(env->tile_acc, s->tile_acc, sizeof(env->tile_acc));
env->tile_acc_bytes = s->tile_acc_bytes;
env->tile_acc_dtype = s->tile_acc_dtype;
env->tile_acc_valid = s->tile_acc_valid;
env->tile_acc_cols = s->tile_acc_cols;
env->tile_acc_rows = s->tile_acc_rows;
}

/*
Expand Down
Loading