mesa/src/nouveau/mme/mme_fermi.c

304 lines
9.0 KiB
C

/*
* Copyright © 2022 Mary Guillemard
* SPDX-License-Identifier: MIT
*/
#include "mme_fermi.h"
#include "mme_bitpack_helpers.h"
#define OP_TO_STR(OP) [MME_FERMI_OP_##OP] = #OP
static const char *op_to_str[] = {
OP_TO_STR(ALU_REG),
OP_TO_STR(ADD_IMM),
OP_TO_STR(MERGE),
OP_TO_STR(BFE_LSL_IMM),
OP_TO_STR(BFE_LSL_REG),
OP_TO_STR(STATE),
OP_TO_STR(UNK6),
OP_TO_STR(BRANCH),
};
#undef OP_TO_STR
const char *
mme_fermi_op_to_str(enum mme_fermi_op op)
{
assert(op < ARRAY_SIZE(op_to_str));
return op_to_str[op];
}
#define ALU_OP_TO_STR(OP) [MME_FERMI_ALU_OP_##OP] = #OP
static const char *alu_op_to_str[] = {
ALU_OP_TO_STR(ADD),
ALU_OP_TO_STR(ADDC),
ALU_OP_TO_STR(SUB),
ALU_OP_TO_STR(SUBB),
ALU_OP_TO_STR(RESERVED4),
ALU_OP_TO_STR(RESERVED5),
ALU_OP_TO_STR(RESERVED6),
ALU_OP_TO_STR(RESERVED7),
ALU_OP_TO_STR(XOR),
ALU_OP_TO_STR(OR),
ALU_OP_TO_STR(AND),
ALU_OP_TO_STR(AND_NOT),
ALU_OP_TO_STR(NAND),
ALU_OP_TO_STR(RESERVED13),
ALU_OP_TO_STR(RESERVED14),
ALU_OP_TO_STR(RESERVED15),
ALU_OP_TO_STR(RESERVED16),
ALU_OP_TO_STR(RESERVED17),
ALU_OP_TO_STR(RESERVED18),
ALU_OP_TO_STR(RESERVED19),
ALU_OP_TO_STR(RESERVED20),
ALU_OP_TO_STR(RESERVED21),
ALU_OP_TO_STR(RESERVED22),
ALU_OP_TO_STR(RESERVED23),
ALU_OP_TO_STR(RESERVED24),
ALU_OP_TO_STR(RESERVED25),
ALU_OP_TO_STR(RESERVED26),
ALU_OP_TO_STR(RESERVED27),
ALU_OP_TO_STR(RESERVED28),
ALU_OP_TO_STR(RESERVED29),
ALU_OP_TO_STR(RESERVED30),
ALU_OP_TO_STR(RESERVED31),
};
#undef ALU_OP_TO_STR
const char *
mme_fermi_alu_op_to_str(enum mme_fermi_alu_op op)
{
assert(op < ARRAY_SIZE(alu_op_to_str));
return alu_op_to_str[op];
}
#define ASSIGN_OP_TO_STR(OP) [MME_FERMI_ASSIGN_OP_##OP] = #OP
static const char *assign_op_to_str[] = {
ASSIGN_OP_TO_STR(LOAD),
ASSIGN_OP_TO_STR(MOVE),
ASSIGN_OP_TO_STR(MOVE_SET_MADDR),
ASSIGN_OP_TO_STR(LOAD_EMIT),
ASSIGN_OP_TO_STR(MOVE_EMIT),
ASSIGN_OP_TO_STR(LOAD_SET_MADDR),
ASSIGN_OP_TO_STR(MOVE_SET_MADDR_LOAD_EMIT),
ASSIGN_OP_TO_STR(MOVE_SET_MADDR_LOAD_EMIT_HIGH),
};
#undef ASSIGN_OP_TO_STR
const char *
mme_fermi_assign_op_to_str(enum mme_fermi_assign_op op)
{
assert(op < ARRAY_SIZE(assign_op_to_str));
return assign_op_to_str[op];
}
void mme_fermi_encode(uint32_t *out, uint32_t inst_count,
const struct mme_fermi_inst *insts)
{
for (uint32_t i = 0; i < inst_count; i++) {
uint32_t *b = &out[i];
*b = 0;
pack_uint(b, 0, 3, insts[i].op);
pack_uint(b, 7, 7, insts[i].end_next);
pack_uint(b, 8, 10, insts[i].dst);
if (insts[i].op != MME_FERMI_OP_BRANCH) {
pack_uint(b, 4, 6, insts[i].assign_op);
}
if (insts[i].op == MME_FERMI_OP_ALU_REG) {
pack_uint(b, 11, 13, insts[i].src[0]);
pack_uint(b, 14, 16, insts[i].src[1]);
pack_uint(b, 17, 21, insts[i].alu_op);
} else if (insts[i].op == MME_FERMI_OP_ADD_IMM ||
insts[i].op == MME_FERMI_OP_STATE) {
pack_uint(b, 11, 13, insts[i].src[0]);
pack_sint(b, 14, 31, insts[i].imm);
} else if (insts[i].op == MME_FERMI_OP_MERGE ||
insts[i].op == MME_FERMI_OP_BFE_LSL_IMM ||
insts[i].op == MME_FERMI_OP_BFE_LSL_REG) {
pack_uint(b, 11, 13, insts[i].src[0]);
pack_uint(b, 14, 16, insts[i].src[1]);
pack_uint(b, 17, 21, insts[i].bitfield.src_bit);
pack_uint(b, 22, 26, insts[i].bitfield.size);
pack_uint(b, 27, 31, insts[i].bitfield.dst_bit);
} else if (insts[i].op == MME_FERMI_OP_BRANCH) {
pack_uint(b, 4, 4, insts[i].branch.not_zero);
pack_uint(b, 5, 5, insts[i].branch.no_delay);
pack_uint(b, 11, 13, insts[i].src[0]);
pack_sint(b, 14, 31, insts[i].imm);
}
}
}
void mme_fermi_decode(struct mme_fermi_inst *insts,
const uint32_t *in, uint32_t inst_count)
{
for (uint32_t i = 0; i < inst_count; i++) {
const uint32_t *b = &in[i];
insts[i].op = unpack_uint(b, 0, 3);
insts[i].end_next = unpack_uint(b, 7, 7);
insts[i].dst = unpack_uint(b, 8, 10);
if (insts[i].op != MME_FERMI_OP_BRANCH) {
insts[i].assign_op = unpack_uint(b, 4, 6);
}
if (insts[i].op == MME_FERMI_OP_ALU_REG) {
insts[i].src[0] = unpack_uint(b, 11, 13);
insts[i].src[1] = unpack_uint(b, 14, 16);
insts[i].alu_op = unpack_uint(b, 17, 21);
} else if (insts[i].op == MME_FERMI_OP_ADD_IMM ||
insts[i].op == MME_FERMI_OP_STATE) {
insts[i].src[0] = unpack_uint(b, 11, 13);
insts[i].imm = unpack_sint(b, 14, 31);
} else if (insts[i].op == MME_FERMI_OP_MERGE ||
insts[i].op == MME_FERMI_OP_BFE_LSL_IMM ||
insts[i].op == MME_FERMI_OP_BFE_LSL_REG) {
insts[i].src[0] = unpack_uint(b, 11, 13);
insts[i].src[1] = unpack_uint(b, 14, 16);
insts[i].bitfield.src_bit = unpack_uint(b, 17, 21);
insts[i].bitfield.size = unpack_uint(b, 22, 26);
insts[i].bitfield.dst_bit = unpack_uint(b, 27, 31);
} else if (insts[i].op == MME_FERMI_OP_BRANCH) {
insts[i].branch.not_zero = unpack_uint(b, 4, 4);
insts[i].branch.no_delay = unpack_uint(b, 5, 5);
insts[i].src[0] = unpack_uint(b, 11, 13);
insts[i].imm = unpack_sint(b, 14, 31);
}
}
}
static void
print_indent(FILE *fp, unsigned depth)
{
for (unsigned i = 0; i < depth; i++)
fprintf(fp, " ");
}
static void
print_reg(FILE *fp, enum mme_fermi_reg reg)
{
if (reg == MME_FERMI_REG_ZERO) {
fprintf(fp, " $zero");
} else {
fprintf(fp, " $r%u", (unsigned)reg);
}
}
static void
print_imm(FILE *fp, const struct mme_fermi_inst *inst)
{
int32_t imm = util_mask_sign_extend(inst->imm, 18);
fprintf(fp, " %d /* 0x%04x */", (int)imm, (unsigned)imm);
}
void
mme_fermi_print_inst(FILE *fp, unsigned indent,
const struct mme_fermi_inst *inst)
{
print_indent(fp, indent);
switch (inst->op) {
case MME_FERMI_OP_ALU_REG:
fprintf(fp, "%s", mme_fermi_alu_op_to_str(inst->alu_op));
print_reg(fp, inst->src[0]);
print_reg(fp, inst->src[1]);
if (inst->alu_op == MME_FERMI_ALU_OP_ADDC) {
fprintf(fp, " $carry");
} else if (inst->alu_op == MME_FERMI_ALU_OP_SUBB) {
fprintf(fp, " $borrow");
}
break;
case MME_FERMI_OP_ADD_IMM:
case MME_FERMI_OP_STATE:
fprintf(fp, "%s", mme_fermi_op_to_str(inst->op));
print_reg(fp, inst->src[0]);
print_imm(fp, inst);
break;
case MME_FERMI_OP_MERGE:
fprintf(fp, "%s", mme_fermi_op_to_str(inst->op));
print_reg(fp, inst->src[0]);
print_reg(fp, inst->src[1]);
fprintf(fp, " (%u, %u, %u)", inst->bitfield.src_bit,
inst->bitfield.size,
inst->bitfield.dst_bit);
break;
case MME_FERMI_OP_BFE_LSL_IMM:
fprintf(fp, "%s", mme_fermi_op_to_str(inst->op));
print_reg(fp, inst->src[0]);
print_reg(fp, inst->src[1]);
fprintf(fp, " (%u, %u)", inst->bitfield.dst_bit,
inst->bitfield.size);
break;
case MME_FERMI_OP_BFE_LSL_REG:
fprintf(fp, "%s", mme_fermi_op_to_str(inst->op));
print_reg(fp, inst->src[0]);
print_reg(fp, inst->src[1]);
fprintf(fp, " (%u, %u)", inst->bitfield.src_bit,
inst->bitfield.size);
break;
case MME_FERMI_OP_BRANCH:
if (inst->branch.not_zero) {
fprintf(fp, "BNZ");
} else {
fprintf(fp, "BZ");
}
print_reg(fp, inst->src[0]);
print_imm(fp, inst);
if (inst->branch.no_delay) {
fprintf(fp, " NO_DELAY");
}
break;
default:
fprintf(fp, "%s", mme_fermi_op_to_str(inst->op));
break;
}
if (inst->op != MME_FERMI_OP_BRANCH) {
fprintf(fp, "\n");
print_indent(fp, indent);
fprintf(fp, "%s", mme_fermi_assign_op_to_str(inst->assign_op));
print_reg(fp, inst->dst);
if (inst->assign_op != MME_FERMI_ASSIGN_OP_LOAD) {
fprintf(fp, " $scratch");
}
}
if (inst->end_next) {
fprintf(fp, "\n");
print_indent(fp, indent);
fprintf(fp, "END_NEXT");
}
fprintf(fp, "\n");
}
void
mme_fermi_print(FILE *fp, const struct mme_fermi_inst *insts,
uint32_t inst_count)
{
for (uint32_t i = 0; i < inst_count; i++) {
fprintf(fp, "%u:\n", i);
mme_fermi_print_inst(fp, 1, &insts[i]);
}
}
void
mme_fermi_dump(FILE *fp, uint32_t *encoded, size_t encoded_size)
{
uint32_t inst_count = encoded_size / 4;
for (uint32_t i = 0; i < inst_count; i++) {
struct mme_fermi_inst inst;
mme_fermi_decode(&inst, &encoded[i], 1);
mme_fermi_print_inst(fp, 1, &inst);
}
}