broadcom: Add V3D 3.3 QPU instruction pack, unpack, and disasm.

Unlike VC4, I've defined an unpacked instruction format with pack/unpack
functions to convert to 64-bit encoded instructions.  This will let us
incrementally put together our instructions and validate them in a more
natural way than the QPU_GET_FIELD/QPU_SET_FIELD used to.

The pack/unpack unfortuantely are written by hand.  While I could define
genxml for parts of it, there are many special cases (like operand order
of commutative binops choosing which binop is being performed!) and it
probably wouldn't come out much cleaner.

The disasm unit test ensures that we have the same assembly format as
Broadcom's internal tools, other than whitespace changes.

v2: Fix automake variable redefinition complaints, add test to .gitignore
This commit is contained in:
Eric Anholt
2017-02-02 16:15:18 -08:00
parent 59257c35eb
commit 05c7d9715b
12 changed files with 2774 additions and 0 deletions

View File

@@ -1,2 +1,3 @@
cle/v3d_xml.h
cle/*_pack.h
qpu/tests/qpu_disasm

View File

@@ -24,6 +24,8 @@ AM_CPPFLAGS = \
-I$(top_srcdir)/include \
-I$(top_builddir)/src \
-I$(top_srcdir)/src \
-I$(top_srcdir)/src/broadcom/ \
-I$(top_srcdir)/src/broadcom/include \
$(VALGRIND_CFLAGS) \
$(DEFINES)
@@ -49,5 +51,6 @@ PYTHON_GEN = $(AM_V_GEN)$(PYTHON2) $(PYTHON_FLAGS)
include Makefile.genxml.am
include Makefile.cle.am
include Makefile.vc5.am
CLEANFILES += $(BUILT_SOURCES)

View File

@@ -14,6 +14,11 @@ BROADCOM_FILES = \
common/v3d_debug.c \
common/v3d_debug.h \
common/v3d_device_info.h \
qpu/qpu_disasm.c \
qpu/qpu_disasm.h \
qpu/qpu_instr.c \
qpu/qpu_instr.h \
qpu/qpu_pack.c \
$()
BROADCOM_DECODER_FILES = \

View File

@@ -0,0 +1,19 @@
noinst_LTLIBRARIES += libbroadcom.la
if USE_VC5_SIMULATOR
AM_CFLAGS += $(VC5_SIMULATOR_CFLAGS)
libbroadcom_la_LDFLAGS = $(VC5_SIMULATOR_LIBS)
endif
libbroadcom_la_SOURCES = $(BROADCOM_FILES)
check_PROGRAMS += \
qpu/tests/qpu_disasm \
$(NULL)
LDADD = \
libbroadcom.la \
$(top_builddir)/src/util/libmesautil.la \
$(NULL)
TESTS += $(check_PROGRAMS)

View File

@@ -0,0 +1,298 @@
/*
* Copyright © 2016 Broadcom
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <string.h>
#include <stdio.h>
#include "util/ralloc.h"
#include "broadcom/common/v3d_device_info.h"
#include "qpu_instr.h"
#include "qpu_disasm.h"
struct disasm_state {
const struct v3d_device_info *devinfo;
char *string;
size_t offset;
};
static void
append(struct disasm_state *disasm, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
ralloc_vasprintf_rewrite_tail(&disasm->string,
&disasm->offset,
fmt, args);
va_end(args);
}
static void
pad_to(struct disasm_state *disasm, int n)
{
/* FIXME: Do a single append somehow. */
while (disasm->offset < n)
append(disasm, " ");
}
static void
v3d_qpu_disasm_raddr(struct disasm_state *disasm,
const struct v3d_qpu_instr *instr, uint8_t mux)
{
if (mux == V3D_QPU_MUX_A) {
append(disasm, "rf%d", instr->raddr_a);
} else if (mux == V3D_QPU_MUX_B) {
append(disasm, "rf%d", instr->raddr_b);
} else {
append(disasm, "r%d", mux);
}
}
static void
v3d_qpu_disasm_waddr(struct disasm_state *disasm, uint32_t waddr, bool magic)
{
if (!magic) {
append(disasm, "rf%d", waddr);
return;
}
const char *name = v3d_qpu_magic_waddr_name(waddr);
if (name)
append(disasm, "%s", name);
else
append(disasm, "waddr UNKNOWN %d", waddr);
}
static void
v3d_qpu_disasm_add(struct disasm_state *disasm,
const struct v3d_qpu_instr *instr)
{
bool has_dst = v3d_qpu_add_op_has_dst(instr->alu.add.op);
int num_src = v3d_qpu_add_op_num_src(instr->alu.add.op);
append(disasm, "%s", v3d_qpu_add_op_name(instr->alu.add.op));
append(disasm, "%s", v3d_qpu_cond_name(instr->flags.ac));
append(disasm, "%s", v3d_qpu_pf_name(instr->flags.apf));
append(disasm, "%s", v3d_qpu_uf_name(instr->flags.auf));
append(disasm, " ");
if (has_dst) {
v3d_qpu_disasm_waddr(disasm, instr->alu.add.waddr,
instr->alu.add.magic_write);
append(disasm, v3d_qpu_pack_name(instr->alu.add.output_pack));
}
if (num_src >= 1) {
if (has_dst)
append(disasm, ", ");
v3d_qpu_disasm_raddr(disasm, instr, instr->alu.add.a);
append(disasm, "%s",
v3d_qpu_unpack_name(instr->alu.add.a_unpack));
}
if (num_src >= 2) {
append(disasm, ", ");
v3d_qpu_disasm_raddr(disasm, instr, instr->alu.add.b);
append(disasm, "%s",
v3d_qpu_unpack_name(instr->alu.add.b_unpack));
}
}
static void
v3d_qpu_disasm_mul(struct disasm_state *disasm,
const struct v3d_qpu_instr *instr)
{
bool has_dst = v3d_qpu_mul_op_has_dst(instr->alu.mul.op);
int num_src = v3d_qpu_mul_op_num_src(instr->alu.mul.op);
pad_to(disasm, 21);
append(disasm, "; ");
append(disasm, "%s", v3d_qpu_mul_op_name(instr->alu.mul.op));
append(disasm, "%s", v3d_qpu_cond_name(instr->flags.mc));
append(disasm, "%s", v3d_qpu_pf_name(instr->flags.mpf));
append(disasm, "%s", v3d_qpu_uf_name(instr->flags.muf));
if (instr->alu.mul.op == V3D_QPU_M_NOP)
return;
append(disasm, " ");
if (has_dst) {
v3d_qpu_disasm_waddr(disasm, instr->alu.mul.waddr,
instr->alu.mul.magic_write);
append(disasm, v3d_qpu_pack_name(instr->alu.mul.output_pack));
}
if (num_src >= 1) {
if (has_dst)
append(disasm, ", ");
v3d_qpu_disasm_raddr(disasm, instr, instr->alu.mul.a);
append(disasm, "%s",
v3d_qpu_unpack_name(instr->alu.mul.a_unpack));
}
if (num_src >= 2) {
append(disasm, ", ");
v3d_qpu_disasm_raddr(disasm, instr, instr->alu.mul.b);
append(disasm, "%s",
v3d_qpu_unpack_name(instr->alu.mul.b_unpack));
}
}
static void
v3d_qpu_disasm_sig(struct disasm_state *disasm,
const struct v3d_qpu_instr *instr)
{
const struct v3d_qpu_sig *sig = &instr->sig;
if (!sig->thrsw &&
!sig->ldvary &&
!sig->ldvpm &&
!sig->ldtmu &&
!sig->ldunif &&
!sig->wrtmuc) {
return;
}
pad_to(disasm, 41);
if (sig->thrsw)
append(disasm, "; thrsw");
if (sig->ldvary)
append(disasm, "; ldvary");
if (sig->ldvpm)
append(disasm, "; ldvpm");
if (sig->ldtmu)
append(disasm, "; ldtmu");
if (sig->ldunif)
append(disasm, "; ldunif");
if (sig->wrtmuc)
append(disasm, "; wrtmuc");
}
static void
v3d_qpu_disasm_alu(struct disasm_state *disasm,
const struct v3d_qpu_instr *instr)
{
v3d_qpu_disasm_add(disasm, instr);
v3d_qpu_disasm_mul(disasm, instr);
v3d_qpu_disasm_sig(disasm, instr);
}
static void
v3d_qpu_disasm_branch(struct disasm_state *disasm,
const struct v3d_qpu_instr *instr)
{
append(disasm, "b");
if (instr->branch.ub)
append(disasm, "u");
append(disasm, "%s", v3d_qpu_branch_cond_name(instr->branch.cond));
append(disasm, "%s", v3d_qpu_msfign_name(instr->branch.msfign));
switch (instr->branch.bdi) {
case V3D_QPU_BRANCH_DEST_ABS:
append(disasm, " zero_addr+0x%08x", instr->branch.offset);
break;
case V3D_QPU_BRANCH_DEST_REL:
append(disasm, " %d", instr->branch.offset);
break;
case V3D_QPU_BRANCH_DEST_LINK_REG:
append(disasm, " lri");
break;
case V3D_QPU_BRANCH_DEST_REGFILE:
append(disasm, " rf%d", instr->branch.raddr_a);
break;
}
if (instr->branch.ub) {
switch (instr->branch.bdu) {
case V3D_QPU_BRANCH_DEST_ABS:
append(disasm, ", a:unif");
break;
case V3D_QPU_BRANCH_DEST_REL:
append(disasm, ", r:unif");
break;
case V3D_QPU_BRANCH_DEST_LINK_REG:
append(disasm, ", lri");
break;
case V3D_QPU_BRANCH_DEST_REGFILE:
append(disasm, ", rf%d", instr->branch.raddr_a);
break;
}
}
}
const char *
v3d_qpu_decode(const struct v3d_device_info *devinfo,
const struct v3d_qpu_instr *instr)
{
struct disasm_state disasm = {
.string = rzalloc_size(NULL, 1),
.offset = 0,
.devinfo = devinfo,
};
switch (instr->type) {
case V3D_QPU_INSTR_TYPE_ALU:
v3d_qpu_disasm_alu(&disasm, instr);
break;
case V3D_QPU_INSTR_TYPE_BRANCH:
v3d_qpu_disasm_branch(&disasm, instr);
break;
}
return disasm.string;
}
/**
* Returns a string containing the disassembled representation of the QPU
* instruction. It is the caller's responsibility to free the return value
* with ralloc_free().
*/
const char *
v3d_qpu_disasm(const struct v3d_device_info *devinfo, uint64_t inst)
{
struct v3d_qpu_instr instr;
bool ok = v3d_qpu_instr_unpack(devinfo, inst, &instr);
assert(ok); (void)ok;
return v3d_qpu_decode(devinfo, &instr);
}
void
v3d_qpu_dump(const struct v3d_device_info *devinfo,
const struct v3d_qpu_instr *instr)
{
const char *decoded = v3d_qpu_decode(devinfo, instr);
fprintf(stderr, "%s", decoded);
ralloc_free((char *)decoded);
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright © 2016 Broadcom
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef VC5_QPU_DISASM_H
#define VC5_QPU_DISASM_H
#include "broadcom/common/v3d_device_info.h"
struct v3d_qpu_instr;
const char *v3d_qpu_decode(const struct v3d_device_info *devinfo, const
struct v3d_qpu_instr *instr);
const char *v3d_qpu_disasm(const struct v3d_device_info *devinfo, uint64_t inst);
void v3d_qpu_dump(const struct v3d_device_info *devinfo, const
struct v3d_qpu_instr *instr);
#endif /* VC5_QPU_DISASM_H */

View File

@@ -0,0 +1,645 @@
/*
* Copyright © 2016 Broadcom
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <stdlib.h>
#include "util/macros.h"
#include "qpu_instr.h"
#ifndef QPU_MASK
#define QPU_MASK(high, low) ((((uint64_t)1<<((high)-(low)+1))-1)<<(low))
/* Using the GNU statement expression extension */
#define QPU_SET_FIELD(value, field) \
({ \
uint64_t fieldval = (uint64_t)(value) << field ## _SHIFT; \
assert((fieldval & ~ field ## _MASK) == 0); \
fieldval & field ## _MASK; \
})
#define QPU_GET_FIELD(word, field) ((uint32_t)(((word) & field ## _MASK) >> field ## _SHIFT))
#define QPU_UPDATE_FIELD(inst, value, field) \
(((inst) & ~(field ## _MASK)) | QPU_SET_FIELD(value, field))
#endif /* QPU_MASK */
#define VC5_QPU_OP_MUL_SHIFT 58
#define VC5_QPU_OP_MUL_MASK QPU_MASK(63, 58)
#define VC5_QPU_SIG_SHIFT 53
#define VC5_QPU_SIG_MASK QPU_MASK(57, 53)
# define VC5_QPU_SIG_THRSW_BIT 0x1
# define VC5_QPU_SIG_LDUNIF_BIT 0x2
# define VC5_QPU_SIG_LDTMU_BIT 0x4
# define VC5_QPU_SIG_LDVARY_BIT 0x8
#define VC5_QPU_COND_SHIFT 46
#define VC5_QPU_COND_MASK QPU_MASK(52, 46)
#define VC5_QPU_COND_IFA 0
#define VC5_QPU_COND_IFB 1
#define VC5_QPU_COND_IFNA 2
#define VC5_QPU_COND_IFNB 3
#define VC5_QPU_MM QPU_MASK(45, 45)
#define VC5_QPU_MA QPU_MASK(44, 44)
#define V3D_QPU_WADDR_M_SHIFT 38
#define V3D_QPU_WADDR_M_MASK QPU_MASK(43, 38)
#define VC5_QPU_BRANCH_ADDR_LOW_SHIFT 35
#define VC5_QPU_BRANCH_ADDR_LOW_MASK QPU_MASK(55, 35)
#define V3D_QPU_WADDR_A_SHIFT 32
#define V3D_QPU_WADDR_A_MASK QPU_MASK(37, 32)
#define VC5_QPU_BRANCH_COND_SHIFT 32
#define VC5_QPU_BRANCH_COND_MASK QPU_MASK(34, 32)
#define VC5_QPU_BRANCH_ADDR_HIGH_SHIFT 24
#define VC5_QPU_BRANCH_ADDR_HIGH_MASK QPU_MASK(31, 24)
#define VC5_QPU_OP_ADD_SHIFT 24
#define VC5_QPU_OP_ADD_MASK QPU_MASK(31, 24)
#define VC5_QPU_MUL_B_SHIFT 21
#define VC5_QPU_MUL_B_MASK QPU_MASK(23, 21)
#define VC5_QPU_BRANCH_MSFIGN_SHIFT 21
#define VC5_QPU_BRANCH_MSFIGN_MASK QPU_MASK(22, 21)
#define VC5_QPU_MUL_A_SHIFT 18
#define VC5_QPU_MUL_A_MASK QPU_MASK(20, 18)
#define VC5_QPU_ADD_B_SHIFT 15
#define VC5_QPU_ADD_B_MASK QPU_MASK(17, 15)
#define VC5_QPU_BRANCH_BDU_SHIFT 15
#define VC5_QPU_BRANCH_BDU_MASK QPU_MASK(17, 15)
#define VC5_QPU_BRANCH_UB QPU_MASK(14, 14)
#define VC5_QPU_ADD_A_SHIFT 12
#define VC5_QPU_ADD_A_MASK QPU_MASK(14, 12)
#define VC5_QPU_BRANCH_BDI_SHIFT 12
#define VC5_QPU_BRANCH_BDI_MASK QPU_MASK(13, 12)
#define VC5_QPU_RADDR_A_SHIFT 6
#define VC5_QPU_RADDR_A_MASK QPU_MASK(11, 6)
#define VC5_QPU_RADDR_B_SHIFT 0
#define VC5_QPU_RADDR_B_MASK QPU_MASK(5, 0)
const char *
v3d_qpu_magic_waddr_name(enum v3d_qpu_waddr waddr)
{
static const char *waddr_magic[] = {
[V3D_QPU_WADDR_R0] = "r0",
[V3D_QPU_WADDR_R1] = "r1",
[V3D_QPU_WADDR_R2] = "r2",
[V3D_QPU_WADDR_R3] = "r3",
[V3D_QPU_WADDR_R4] = "r4",
[V3D_QPU_WADDR_R5] = "r5",
[V3D_QPU_WADDR_NOP] = "-",
[V3D_QPU_WADDR_TLB] = "tlb",
[V3D_QPU_WADDR_TLBU] = "tlbu",
[V3D_QPU_WADDR_TMU] = "tmu",
[V3D_QPU_WADDR_TMUL] = "tmul",
[V3D_QPU_WADDR_TMUD] = "tmud",
[V3D_QPU_WADDR_TMUA] = "tmua",
[V3D_QPU_WADDR_TMUAU] = "tmuau",
[V3D_QPU_WADDR_VPM] = "vpm",
[V3D_QPU_WADDR_VPMU] = "vpmu",
[V3D_QPU_WADDR_SYNC] = "sync",
[V3D_QPU_WADDR_SYNCU] = "syncu",
[V3D_QPU_WADDR_RECIP] = "recip",
[V3D_QPU_WADDR_RSQRT] = "rsqrt",
[V3D_QPU_WADDR_EXP] = "exp",
[V3D_QPU_WADDR_LOG] = "log",
[V3D_QPU_WADDR_SIN] = "sin",
[V3D_QPU_WADDR_RSQRT2] = "rsqrt2",
};
return waddr_magic[waddr];
}
const char *
v3d_qpu_add_op_name(enum v3d_qpu_add_op op)
{
static const char *op_names[] = {
[V3D_QPU_A_FADD] = "fadd",
[V3D_QPU_A_FADDNF] = "faddnf",
[V3D_QPU_A_VFPACK] = "vfpack",
[V3D_QPU_A_ADD] = "add",
[V3D_QPU_A_SUB] = "sub",
[V3D_QPU_A_FSUB] = "fsub",
[V3D_QPU_A_MIN] = "min",
[V3D_QPU_A_MAX] = "max",
[V3D_QPU_A_UMIN] = "umin",
[V3D_QPU_A_UMAX] = "umax",
[V3D_QPU_A_SHL] = "shl",
[V3D_QPU_A_SHR] = "shr",
[V3D_QPU_A_ASR] = "asr",
[V3D_QPU_A_ROR] = "ror",
[V3D_QPU_A_FMIN] = "fmin",
[V3D_QPU_A_FMAX] = "fmax",
[V3D_QPU_A_VFMIN] = "vfmin",
[V3D_QPU_A_AND] = "and",
[V3D_QPU_A_OR] = "or",
[V3D_QPU_A_XOR] = "xor",
[V3D_QPU_A_VADD] = "vadd",
[V3D_QPU_A_VSUB] = "vsub",
[V3D_QPU_A_NOT] = "not",
[V3D_QPU_A_NEG] = "neg",
[V3D_QPU_A_FLAPUSH] = "flapush",
[V3D_QPU_A_FLBPUSH] = "flbpush",
[V3D_QPU_A_FLBPOP] = "flbpop",
[V3D_QPU_A_SETMSF] = "setmsf",
[V3D_QPU_A_SETREVF] = "setrevf",
[V3D_QPU_A_NOP] = "nop",
[V3D_QPU_A_TIDX] = "tidx",
[V3D_QPU_A_EIDX] = "eidx",
[V3D_QPU_A_LR] = "lr",
[V3D_QPU_A_VFLA] = "vfla",
[V3D_QPU_A_VFLNA] = "vflna",
[V3D_QPU_A_VFLB] = "vflb",
[V3D_QPU_A_VFLNB] = "vflnb",
[V3D_QPU_A_FXCD] = "fxcd",
[V3D_QPU_A_XCD] = "xcd",
[V3D_QPU_A_FYCD] = "fycd",
[V3D_QPU_A_YCD] = "ycd",
[V3D_QPU_A_MSF] = "msf",
[V3D_QPU_A_REVF] = "revf",
[V3D_QPU_A_VDWWT] = "vdwwt",
[V3D_QPU_A_IID] = "iid",
[V3D_QPU_A_SAMPID] = "sampid",
[V3D_QPU_A_PATCHID] = "patchid",
[V3D_QPU_A_TMUWT] = "tmuwt",
[V3D_QPU_A_VPMSETUP] = "vpmsetup",
[V3D_QPU_A_VPMWT] = "vpmwt",
[V3D_QPU_A_LDVPMV] = "ldvpmv",
[V3D_QPU_A_LDVPMD] = "ldvpmd",
[V3D_QPU_A_LDVPMP] = "ldvpmp",
[V3D_QPU_A_LDVPMG] = "ldvpmg",
[V3D_QPU_A_FCMP] = "fcmp",
[V3D_QPU_A_VFMAX] = "vfmax",
[V3D_QPU_A_FROUND] = "fround",
[V3D_QPU_A_FTOIN] = "ftoin",
[V3D_QPU_A_FTRUNC] = "ftrunc",
[V3D_QPU_A_FTOIZ] = "ftoiz",
[V3D_QPU_A_FFLOOR] = "ffloor",
[V3D_QPU_A_FTOUZ] = "ftouz",
[V3D_QPU_A_FCEIL] = "fceil",
[V3D_QPU_A_FTOC] = "ftoc",
[V3D_QPU_A_FDX] = "fdx",
[V3D_QPU_A_FDY] = "fdy",
[V3D_QPU_A_STVPMV] = "stvpmv",
[V3D_QPU_A_STVPMD] = "stvpmd",
[V3D_QPU_A_STVPMP] = "stvpmp",
[V3D_QPU_A_ITOF] = "itof",
[V3D_QPU_A_CLZ] = "clz",
[V3D_QPU_A_UTOF] = "utof",
};
if (op >= ARRAY_SIZE(op_names))
return NULL;
return op_names[op];
}
const char *
v3d_qpu_mul_op_name(enum v3d_qpu_mul_op op)
{
static const char *op_names[] = {
[V3D_QPU_M_ADD] = "add",
[V3D_QPU_M_SUB] = "sub",
[V3D_QPU_M_UMUL24] = "umul24",
[V3D_QPU_M_VFMUL] = "vfmul",
[V3D_QPU_M_SMUL24] = "smul24",
[V3D_QPU_M_MULTOP] = "multop",
[V3D_QPU_M_FMOV] = "fmov",
[V3D_QPU_M_MOV] = "mov",
[V3D_QPU_M_NOP] = "nop",
[V3D_QPU_M_FMUL] = "fmul",
};
if (op >= ARRAY_SIZE(op_names))
return NULL;
return op_names[op];
}
const char *
v3d_qpu_cond_name(enum v3d_qpu_cond cond)
{
switch (cond) {
case V3D_QPU_COND_NONE:
return "";
case V3D_QPU_COND_IFA:
return ".ifa";
case V3D_QPU_COND_IFB:
return ".ifb";
case V3D_QPU_COND_IFNA:
return ".ifna";
case V3D_QPU_COND_IFNB:
return ".ifnb";
default:
unreachable("bad cond value");
}
}
const char *
v3d_qpu_branch_cond_name(enum v3d_qpu_branch_cond cond)
{
switch (cond) {
case V3D_QPU_BRANCH_COND_ALWAYS:
return "";
case V3D_QPU_BRANCH_COND_A0:
return ".a0";
case V3D_QPU_BRANCH_COND_NA0:
return ".na0";
case V3D_QPU_BRANCH_COND_ALLA:
return ".alla";
case V3D_QPU_BRANCH_COND_ANYNA:
return ".anyna";
case V3D_QPU_BRANCH_COND_ANYA:
return ".anya";
case V3D_QPU_BRANCH_COND_ALLNA:
return ".allna";
default:
unreachable("bad branch cond value");
}
}
const char *
v3d_qpu_msfign_name(enum v3d_qpu_msfign msfign)
{
switch (msfign) {
case V3D_QPU_MSFIGN_NONE:
return "";
case V3D_QPU_MSFIGN_P:
return "p";
case V3D_QPU_MSFIGN_Q:
return "q";
default:
unreachable("bad branch cond value");
}
}
const char *
v3d_qpu_pf_name(enum v3d_qpu_pf pf)
{
switch (pf) {
case V3D_QPU_PF_NONE:
return "";
case V3D_QPU_PF_PUSHZ:
return ".pushz";
case V3D_QPU_PF_PUSHN:
return ".pushn";
case V3D_QPU_PF_PUSHC:
return ".pushc";
default:
unreachable("bad pf value");
}
}
const char *
v3d_qpu_uf_name(enum v3d_qpu_uf uf)
{
switch (uf) {
case V3D_QPU_UF_NONE:
return "";
case V3D_QPU_UF_ANDZ:
return ".andz";
case V3D_QPU_UF_ANDNZ:
return ".andnz";
case V3D_QPU_UF_NORZ:
return ".norz";
case V3D_QPU_UF_NORNZ:
return ".nornz";
case V3D_QPU_UF_ANDN:
return ".andn";
case V3D_QPU_UF_ANDNN:
return ".andnn";
case V3D_QPU_UF_NORN:
return ".norn";
case V3D_QPU_UF_NORNN:
return ".nornn";
case V3D_QPU_UF_ANDC:
return ".andc";
case V3D_QPU_UF_ANDNC:
return ".andnc";
case V3D_QPU_UF_NORC:
return ".norc";
case V3D_QPU_UF_NORNC:
return ".nornc";
default:
unreachable("bad pf value");
}
}
const char *
v3d_qpu_pack_name(enum v3d_qpu_output_pack pack)
{
switch (pack) {
case V3D_QPU_PACK_NONE:
return "";
case V3D_QPU_PACK_L:
return ".l";
case V3D_QPU_PACK_H:
return ".h";
default:
unreachable("bad pack value");
}
}
const char *
v3d_qpu_unpack_name(enum v3d_qpu_input_unpack unpack)
{
switch (unpack) {
case V3D_QPU_UNPACK_NONE:
return "";
case V3D_QPU_UNPACK_L:
return ".l";
case V3D_QPU_UNPACK_H:
return ".h";
case V3D_QPU_UNPACK_ABS:
return ".abs";
case V3D_QPU_UNPACK_REPLICATE_32F_16:
return ".ff";
case V3D_QPU_UNPACK_REPLICATE_L_16:
return ".ll";
case V3D_QPU_UNPACK_REPLICATE_H_16:
return ".hh";
case V3D_QPU_UNPACK_SWAP_16:
return ".swp";
default:
unreachable("bad unpack value");
}
}
#define D 1
#define A 2
#define B 4
static const uint8_t add_op_args[] = {
[V3D_QPU_A_FADD] = D | A | B,
[V3D_QPU_A_FADDNF] = D | A | B,
[V3D_QPU_A_VFPACK] = D | A | B,
[V3D_QPU_A_ADD] = D | A | B,
[V3D_QPU_A_VFPACK] = D | A | B,
[V3D_QPU_A_SUB] = D | A | B,
[V3D_QPU_A_VFPACK] = D | A | B,
[V3D_QPU_A_FSUB] = D | A | B,
[V3D_QPU_A_MIN] = D | A | B,
[V3D_QPU_A_MAX] = D | A | B,
[V3D_QPU_A_UMIN] = D | A | B,
[V3D_QPU_A_UMAX] = D | A | B,
[V3D_QPU_A_SHL] = D | A | B,
[V3D_QPU_A_SHR] = D | A | B,
[V3D_QPU_A_ASR] = D | A | B,
[V3D_QPU_A_ROR] = D | A | B,
[V3D_QPU_A_FMIN] = D | A | B,
[V3D_QPU_A_FMAX] = D | A | B,
[V3D_QPU_A_VFMIN] = D | A | B,
[V3D_QPU_A_AND] = D | A | B,
[V3D_QPU_A_OR] = D | A | B,
[V3D_QPU_A_XOR] = D | A | B,
[V3D_QPU_A_VADD] = D | A | B,
[V3D_QPU_A_VSUB] = D | A | B,
[V3D_QPU_A_NOT] = D | A,
[V3D_QPU_A_NEG] = D | A,
[V3D_QPU_A_FLAPUSH] = D | A,
[V3D_QPU_A_FLBPUSH] = D | A,
[V3D_QPU_A_FLBPOP] = D | A,
[V3D_QPU_A_SETMSF] = D | A,
[V3D_QPU_A_SETREVF] = D | A,
[V3D_QPU_A_NOP] = 0,
[V3D_QPU_A_TIDX] = D,
[V3D_QPU_A_EIDX] = D,
[V3D_QPU_A_LR] = D,
[V3D_QPU_A_VFLA] = D,
[V3D_QPU_A_VFLNA] = D,
[V3D_QPU_A_VFLB] = D,
[V3D_QPU_A_VFLNB] = D,
[V3D_QPU_A_FXCD] = D,
[V3D_QPU_A_XCD] = D,
[V3D_QPU_A_FYCD] = D,
[V3D_QPU_A_YCD] = D,
[V3D_QPU_A_MSF] = D,
[V3D_QPU_A_REVF] = D,
[V3D_QPU_A_VDWWT] = D,
[V3D_QPU_A_IID] = D,
[V3D_QPU_A_SAMPID] = D,
[V3D_QPU_A_PATCHID] = D,
[V3D_QPU_A_TMUWT] = D,
[V3D_QPU_A_VPMWT] = D,
[V3D_QPU_A_VPMSETUP] = D | A,
[V3D_QPU_A_LDVPMV] = D | A,
[V3D_QPU_A_LDVPMD] = D | A,
[V3D_QPU_A_LDVPMP] = D | A,
[V3D_QPU_A_LDVPMG] = D | A | B,
/* FIXME: MOVABSNEG */
[V3D_QPU_A_FCMP] = D | A | B,
[V3D_QPU_A_VFMAX] = D | A | B,
[V3D_QPU_A_FROUND] = D | A,
[V3D_QPU_A_FTOIN] = D | A,
[V3D_QPU_A_FTRUNC] = D | A,
[V3D_QPU_A_FTOIZ] = D | A,
[V3D_QPU_A_FFLOOR] = D | A,
[V3D_QPU_A_FTOUZ] = D | A,
[V3D_QPU_A_FCEIL] = D | A,
[V3D_QPU_A_FTOC] = D | A,
[V3D_QPU_A_FDX] = D | A,
[V3D_QPU_A_FDY] = D | A,
[V3D_QPU_A_STVPMV] = A | B,
[V3D_QPU_A_STVPMD] = A | B,
[V3D_QPU_A_STVPMP] = A | B,
[V3D_QPU_A_ITOF] = D | A,
[V3D_QPU_A_CLZ] = D | A,
[V3D_QPU_A_UTOF] = D | A,
};
static const uint8_t mul_op_args[] = {
[V3D_QPU_M_ADD] = D | A | B,
[V3D_QPU_M_SUB] = D | A | B,
[V3D_QPU_M_UMUL24] = D | A | B,
[V3D_QPU_M_VFMUL] = D | A | B,
[V3D_QPU_M_SMUL24] = D | A | B,
[V3D_QPU_M_MULTOP] = D | A | B,
[V3D_QPU_M_FMOV] = D | A,
[V3D_QPU_M_NOP] = 0,
[V3D_QPU_M_MOV] = D | A,
[V3D_QPU_M_FMUL] = D | A | B,
};
bool
v3d_qpu_add_op_has_dst(enum v3d_qpu_add_op op)
{
assert(op < ARRAY_SIZE(add_op_args));
return add_op_args[op] & D;
}
bool
v3d_qpu_mul_op_has_dst(enum v3d_qpu_mul_op op)
{
assert(op < ARRAY_SIZE(mul_op_args));
return mul_op_args[op] & D;
}
int
v3d_qpu_add_op_num_src(enum v3d_qpu_add_op op)
{
assert(op < ARRAY_SIZE(add_op_args));
uint8_t args = add_op_args[op];
if (args & B)
return 2;
else if (args & A)
return 1;
else
return 0;
}
int
v3d_qpu_mul_op_num_src(enum v3d_qpu_mul_op op)
{
assert(op < ARRAY_SIZE(mul_op_args));
uint8_t args = mul_op_args[op];
if (args & B)
return 2;
else if (args & A)
return 1;
else
return 0;
}
bool
v3d_qpu_magic_waddr_is_sfu(enum v3d_qpu_waddr waddr)
{
switch (waddr) {
case V3D_QPU_WADDR_RECIP:
case V3D_QPU_WADDR_RSQRT:
case V3D_QPU_WADDR_EXP:
case V3D_QPU_WADDR_LOG:
case V3D_QPU_WADDR_SIN:
case V3D_QPU_WADDR_RSQRT2:
return true;
default:
return false;
}
}
bool
v3d_qpu_magic_waddr_is_tmu(enum v3d_qpu_waddr waddr)
{
switch (waddr) {
case V3D_QPU_WADDR_TMU:
case V3D_QPU_WADDR_TMUL:
case V3D_QPU_WADDR_TMUD:
case V3D_QPU_WADDR_TMUA:
case V3D_QPU_WADDR_TMUAU:
return true;
default:
return false;
}
}
bool
v3d_qpu_magic_waddr_is_tlb(enum v3d_qpu_waddr waddr)
{
return (waddr == V3D_QPU_WADDR_TLB ||
waddr == V3D_QPU_WADDR_TLBU);
}
bool
v3d_qpu_magic_waddr_is_vpm(enum v3d_qpu_waddr waddr)
{
return (waddr == V3D_QPU_WADDR_VPM ||
waddr == V3D_QPU_WADDR_VPMU);
}
bool
v3d_qpu_magic_waddr_is_tsy(enum v3d_qpu_waddr waddr)
{
return (waddr == V3D_QPU_WADDR_SYNC ||
waddr == V3D_QPU_WADDR_SYNCU);
}
bool
v3d_qpu_writes_r3(const struct v3d_qpu_instr *inst)
{
return inst->sig.ldvary || inst->sig.ldvpm;
}
bool
v3d_qpu_writes_r4(const struct v3d_qpu_instr *inst)
{
if (inst->sig.ldtmu)
return true;
if (inst->type == V3D_QPU_INSTR_TYPE_ALU) {
if (inst->alu.add.magic_write &&
v3d_qpu_magic_waddr_is_sfu(inst->alu.add.waddr)) {
return true;
}
if (inst->alu.mul.magic_write &&
v3d_qpu_magic_waddr_is_sfu(inst->alu.mul.waddr)) {
return true;
}
}
return false;
}
bool
v3d_qpu_writes_r5(const struct v3d_qpu_instr *inst)
{
return inst->sig.ldvary || inst->sig.ldunif;
}
bool
v3d_qpu_uses_mux(const struct v3d_qpu_instr *inst, enum v3d_qpu_mux mux)
{
int add_nsrc = v3d_qpu_add_op_num_src(inst->alu.add.op);
int mul_nsrc = v3d_qpu_mul_op_num_src(inst->alu.mul.op);
return ((add_nsrc > 0 && inst->alu.add.a == mux) ||
(add_nsrc > 1 && inst->alu.add.b == mux) ||
(mul_nsrc > 0 && inst->alu.mul.a == mux) ||
(mul_nsrc > 1 && inst->alu.mul.b == mux));
}

View File

@@ -0,0 +1,411 @@
/*
* Copyright © 2016 Broadcom
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
/**
* @file qpu_instr.h
*
* Definitions of the unpacked form of QPU instructions. Assembly and
* disassembly will use this for talking about instructions, with qpu_encode.c
* and qpu_decode.c handling the pack and unpack of the actual 64-bit QPU
* instruction.
*/
#ifndef QPU_INSTR_H
#define QPU_INSTR_H
#include <stdbool.h>
#include <stdint.h>
#include "util/macros.h"
struct v3d_device_info;
struct v3d_qpu_sig {
bool thrsw:1;
bool ldunif:1;
bool ldtmu:1;
bool ldvary:1;
bool ldvpm:1;
bool ldtlb:1;
bool ldtlbu:1;
bool small_imm:1;
bool ucb:1;
bool rotate:1;
bool wrtmuc:1;
};
enum v3d_qpu_cond {
V3D_QPU_COND_NONE,
V3D_QPU_COND_IFA,
V3D_QPU_COND_IFB,
V3D_QPU_COND_IFNA,
V3D_QPU_COND_IFNB,
};
enum v3d_qpu_pf {
V3D_QPU_PF_NONE,
V3D_QPU_PF_PUSHZ,
V3D_QPU_PF_PUSHN,
V3D_QPU_PF_PUSHC,
};
enum v3d_qpu_uf {
V3D_QPU_UF_NONE,
V3D_QPU_UF_ANDZ,
V3D_QPU_UF_ANDNZ,
V3D_QPU_UF_NORNZ,
V3D_QPU_UF_NORZ,
V3D_QPU_UF_ANDN,
V3D_QPU_UF_ANDNN,
V3D_QPU_UF_NORNN,
V3D_QPU_UF_NORN,
V3D_QPU_UF_ANDC,
V3D_QPU_UF_ANDNC,
V3D_QPU_UF_NORNC,
V3D_QPU_UF_NORC,
};
enum v3d_qpu_waddr {
V3D_QPU_WADDR_R0 = 0,
V3D_QPU_WADDR_R1 = 1,
V3D_QPU_WADDR_R2 = 2,
V3D_QPU_WADDR_R3 = 3,
V3D_QPU_WADDR_R4 = 4,
V3D_QPU_WADDR_R5 = 5,
/* 6 is reserved, but note 3.2.2.8: "Result Writes" */
V3D_QPU_WADDR_NOP = 6,
V3D_QPU_WADDR_TLB = 7,
V3D_QPU_WADDR_TLBU = 8,
V3D_QPU_WADDR_TMU = 9,
V3D_QPU_WADDR_TMUL = 10,
V3D_QPU_WADDR_TMUD = 11,
V3D_QPU_WADDR_TMUA = 12,
V3D_QPU_WADDR_TMUAU = 13,
V3D_QPU_WADDR_VPM = 14,
V3D_QPU_WADDR_VPMU = 15,
V3D_QPU_WADDR_SYNC = 16,
V3D_QPU_WADDR_SYNCU = 17,
/* reserved */
V3D_QPU_WADDR_RECIP = 19,
V3D_QPU_WADDR_RSQRT = 20,
V3D_QPU_WADDR_EXP = 21,
V3D_QPU_WADDR_LOG = 22,
V3D_QPU_WADDR_SIN = 23,
V3D_QPU_WADDR_RSQRT2 = 24,
};
struct v3d_qpu_flags {
enum v3d_qpu_cond ac, mc;
enum v3d_qpu_pf apf, mpf;
enum v3d_qpu_uf auf, muf;
};
enum v3d_qpu_add_op {
V3D_QPU_A_FADD,
V3D_QPU_A_FADDNF,
V3D_QPU_A_VFPACK,
V3D_QPU_A_ADD,
V3D_QPU_A_SUB,
V3D_QPU_A_FSUB,
V3D_QPU_A_MIN,
V3D_QPU_A_MAX,
V3D_QPU_A_UMIN,
V3D_QPU_A_UMAX,
V3D_QPU_A_SHL,
V3D_QPU_A_SHR,
V3D_QPU_A_ASR,
V3D_QPU_A_ROR,
V3D_QPU_A_FMIN,
V3D_QPU_A_FMAX,
V3D_QPU_A_VFMIN,
V3D_QPU_A_AND,
V3D_QPU_A_OR,
V3D_QPU_A_XOR,
V3D_QPU_A_VADD,
V3D_QPU_A_VSUB,
V3D_QPU_A_NOT,
V3D_QPU_A_NEG,
V3D_QPU_A_FLAPUSH,
V3D_QPU_A_FLBPUSH,
V3D_QPU_A_FLBPOP,
V3D_QPU_A_SETMSF,
V3D_QPU_A_SETREVF,
V3D_QPU_A_NOP,
V3D_QPU_A_TIDX,
V3D_QPU_A_EIDX,
V3D_QPU_A_LR,
V3D_QPU_A_VFLA,
V3D_QPU_A_VFLNA,
V3D_QPU_A_VFLB,
V3D_QPU_A_VFLNB,
V3D_QPU_A_FXCD,
V3D_QPU_A_XCD,
V3D_QPU_A_FYCD,
V3D_QPU_A_YCD,
V3D_QPU_A_MSF,
V3D_QPU_A_REVF,
V3D_QPU_A_VDWWT,
V3D_QPU_A_IID,
V3D_QPU_A_SAMPID,
V3D_QPU_A_PATCHID,
V3D_QPU_A_TMUWT,
V3D_QPU_A_VPMSETUP,
V3D_QPU_A_VPMWT,
V3D_QPU_A_LDVPMV,
V3D_QPU_A_LDVPMD,
V3D_QPU_A_LDVPMP,
V3D_QPU_A_LDVPMG,
V3D_QPU_A_FCMP,
V3D_QPU_A_VFMAX,
V3D_QPU_A_FROUND,
V3D_QPU_A_FTOIN,
V3D_QPU_A_FTRUNC,
V3D_QPU_A_FTOIZ,
V3D_QPU_A_FFLOOR,
V3D_QPU_A_FTOUZ,
V3D_QPU_A_FCEIL,
V3D_QPU_A_FTOC,
V3D_QPU_A_FDX,
V3D_QPU_A_FDY,
V3D_QPU_A_STVPMV,
V3D_QPU_A_STVPMD,
V3D_QPU_A_STVPMP,
V3D_QPU_A_ITOF,
V3D_QPU_A_CLZ,
V3D_QPU_A_UTOF,
};
enum v3d_qpu_mul_op {
V3D_QPU_M_ADD,
V3D_QPU_M_SUB,
V3D_QPU_M_UMUL24,
V3D_QPU_M_VFMUL,
V3D_QPU_M_SMUL24,
V3D_QPU_M_MULTOP,
V3D_QPU_M_FMOV,
V3D_QPU_M_MOV,
V3D_QPU_M_NOP,
V3D_QPU_M_FMUL,
};
enum v3d_qpu_output_pack {
V3D_QPU_PACK_NONE,
/**
* Convert to 16-bit float, put in low 16 bits of destination leaving
* high unmodified.
*/
V3D_QPU_PACK_L,
/**
* Convert to 16-bit float, put in high 16 bits of destination leaving
* low unmodified.
*/
V3D_QPU_PACK_H,
};
enum v3d_qpu_input_unpack {
/**
* No-op input unpacking. Note that this enum's value doesn't match
* the packed QPU instruction value of the field (we use 0 so that the
* default on new instruction creation is no-op).
*/
V3D_QPU_UNPACK_NONE,
/** Absolute value. Only available for some operations. */
V3D_QPU_UNPACK_ABS,
/** Convert low 16 bits from 16-bit float to 32-bit float. */
V3D_QPU_UNPACK_L,
/** Convert high 16 bits from 16-bit float to 32-bit float. */
V3D_QPU_UNPACK_H,
/** Convert to 16f and replicate it to the high bits. */
V3D_QPU_UNPACK_REPLICATE_32F_16,
/** Replicate low 16 bits to high */
V3D_QPU_UNPACK_REPLICATE_L_16,
/** Replicate high 16 bits to low */
V3D_QPU_UNPACK_REPLICATE_H_16,
/** Swap high and low 16 bits */
V3D_QPU_UNPACK_SWAP_16,
};
enum v3d_qpu_mux {
V3D_QPU_MUX_R0,
V3D_QPU_MUX_R1,
V3D_QPU_MUX_R2,
V3D_QPU_MUX_R3,
V3D_QPU_MUX_R4,
V3D_QPU_MUX_R5,
V3D_QPU_MUX_A,
V3D_QPU_MUX_B,
};
struct v3d_qpu_alu_instr {
struct {
enum v3d_qpu_add_op op;
enum v3d_qpu_mux a, b;
uint8_t waddr;
bool magic_write;
enum v3d_qpu_output_pack output_pack;
enum v3d_qpu_input_unpack a_unpack;
enum v3d_qpu_input_unpack b_unpack;
} add;
struct {
enum v3d_qpu_mul_op op;
enum v3d_qpu_mux a, b;
uint8_t waddr;
bool magic_write;
enum v3d_qpu_output_pack output_pack;
enum v3d_qpu_input_unpack a_unpack;
enum v3d_qpu_input_unpack b_unpack;
} mul;
};
enum v3d_qpu_branch_cond {
V3D_QPU_BRANCH_COND_ALWAYS,
V3D_QPU_BRANCH_COND_A0,
V3D_QPU_BRANCH_COND_NA0,
V3D_QPU_BRANCH_COND_ALLA,
V3D_QPU_BRANCH_COND_ANYNA,
V3D_QPU_BRANCH_COND_ANYA,
V3D_QPU_BRANCH_COND_ALLNA,
};
enum v3d_qpu_msfign {
/** Ignore multisample flags when determining branch condition. */
V3D_QPU_MSFIGN_NONE,
/**
* If no multisample flags are set in the lane (a pixel in the FS, a
* vertex in the VS), ignore the lane's condition when computing the
* branch condition.
*/
V3D_QPU_MSFIGN_P,
/**
* If no multisample flags are set in a 2x2 quad in the FS, ignore the
* quad's a/b conditions.
*/
V3D_QPU_MSFIGN_Q,
};
enum v3d_qpu_branch_dest {
V3D_QPU_BRANCH_DEST_ABS,
V3D_QPU_BRANCH_DEST_REL,
V3D_QPU_BRANCH_DEST_LINK_REG,
V3D_QPU_BRANCH_DEST_REGFILE,
};
struct v3d_qpu_branch_instr {
enum v3d_qpu_branch_cond cond;
enum v3d_qpu_msfign msfign;
/** Selects how to compute the new IP if the branch is taken. */
enum v3d_qpu_branch_dest bdi;
/**
* Selects how to compute the new uniforms pointer if the branch is
* taken. (ABS/REL implicitly load a uniform and use that)
*/
enum v3d_qpu_branch_dest bdu;
/**
* If set, then udest determines how the uniform stream will branch,
* otherwise the uniform stream is left as is.
*/
bool ub;
uint8_t raddr_a;
uint32_t offset;
};
enum v3d_qpu_instr_type {
V3D_QPU_INSTR_TYPE_ALU,
V3D_QPU_INSTR_TYPE_BRANCH,
};
struct v3d_qpu_instr {
enum v3d_qpu_instr_type type;
struct v3d_qpu_sig sig;
uint8_t raddr_a;
uint8_t raddr_b;
struct v3d_qpu_flags flags;
union {
struct v3d_qpu_alu_instr alu;
struct v3d_qpu_branch_instr branch;
};
};
const char *v3d_qpu_magic_waddr_name(enum v3d_qpu_waddr waddr);
const char *v3d_qpu_add_op_name(enum v3d_qpu_add_op op);
const char *v3d_qpu_mul_op_name(enum v3d_qpu_mul_op op);
const char *v3d_qpu_cond_name(enum v3d_qpu_cond cond);
const char *v3d_qpu_pf_name(enum v3d_qpu_pf pf);
const char *v3d_qpu_uf_name(enum v3d_qpu_uf uf);
const char *v3d_qpu_pack_name(enum v3d_qpu_output_pack pack);
const char *v3d_qpu_unpack_name(enum v3d_qpu_input_unpack unpack);
const char *v3d_qpu_branch_cond_name(enum v3d_qpu_branch_cond cond);
const char *v3d_qpu_msfign_name(enum v3d_qpu_msfign msfign);
bool v3d_qpu_add_op_has_dst(enum v3d_qpu_add_op op);
bool v3d_qpu_mul_op_has_dst(enum v3d_qpu_mul_op op);
int v3d_qpu_add_op_num_src(enum v3d_qpu_add_op op);
int v3d_qpu_mul_op_num_src(enum v3d_qpu_mul_op op);
bool v3d_qpu_sig_pack(const struct v3d_device_info *devinfo,
const struct v3d_qpu_sig *sig,
uint32_t *packed_sig);
bool v3d_qpu_sig_unpack(const struct v3d_device_info *devinfo,
uint32_t packed_sig,
struct v3d_qpu_sig *sig);
bool
v3d_qpu_flags_pack(const struct v3d_device_info *devinfo,
const struct v3d_qpu_flags *cond,
uint32_t *packed_cond);
bool
v3d_qpu_flags_unpack(const struct v3d_device_info *devinfo,
uint32_t packed_cond,
struct v3d_qpu_flags *cond);
bool
v3d_qpu_instr_pack(const struct v3d_device_info *devinfo,
const struct v3d_qpu_instr *instr,
uint64_t *packed_instr);
bool
v3d_qpu_instr_unpack(const struct v3d_device_info *devinfo,
uint64_t packed_instr,
struct v3d_qpu_instr *instr);
bool v3d_qpu_magic_waddr_is_sfu(enum v3d_qpu_waddr waddr) ATTRIBUTE_CONST;
bool v3d_qpu_magic_waddr_is_tmu(enum v3d_qpu_waddr waddr) ATTRIBUTE_CONST;
bool v3d_qpu_magic_waddr_is_tlb(enum v3d_qpu_waddr waddr) ATTRIBUTE_CONST;
bool v3d_qpu_magic_waddr_is_vpm(enum v3d_qpu_waddr waddr) ATTRIBUTE_CONST;
bool v3d_qpu_magic_waddr_is_tsy(enum v3d_qpu_waddr waddr) ATTRIBUTE_CONST;
bool v3d_qpu_writes_r3(const struct v3d_qpu_instr *instr) ATTRIBUTE_CONST;
bool v3d_qpu_writes_r4(const struct v3d_qpu_instr *instr) ATTRIBUTE_CONST;
bool v3d_qpu_writes_r5(const struct v3d_qpu_instr *instr) ATTRIBUTE_CONST;
bool v3d_qpu_uses_mux(const struct v3d_qpu_instr *inst, enum v3d_qpu_mux mux);
#endif

1206
src/broadcom/qpu/qpu_pack.c Normal file

File diff suppressed because it is too large Load Diff

View File

1
src/broadcom/qpu/tests/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
v3d_qpu_disasm

View File

@@ -0,0 +1,146 @@
/*
* Copyright © 2016 Broadcom
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <stdio.h>
#include <string.h>
#include "util/macros.h"
#include "broadcom/common/v3d_device_info.h"
#include "broadcom/qpu/qpu_disasm.h"
#include "broadcom/qpu/qpu_instr.h"
static const struct {
int ver;
uint64_t inst;
const char *expected;
} tests[] = {
{ 33, 0x3d003186bb800000ull, "nop ; nop ; ldvary" },
{ 33, 0x3c20318105829000ull, "fadd r1, r1, r5 ; nop ; thrsw" },
{ 33, 0x3c403186bb81d000ull, "vpmsetup -, r5 ; nop ; ldunif" },
{ 33, 0x3f003186bb800000ull, "nop ; nop ; ldvpm" },
{ 33, 0x3c002380b6edb000ull, "or rf0, r3, r3 ; mov vpm, r3" },
{ 33, 0x57403006bbb80000ull, "nop ; fmul r0, rf0, r5 ; ldvpm; ldunif" },
/* branch conditions */
{ 33, 0x02000006002034c0ull, "b.anyap rf19" },
{ 33, 0x02679356b4201000ull, "b.anyap -1268280496" },
{ 33, 0x02b76a2dd0400000ull, "b.anynaq zero_addr+0xd0b76a28" },
{ 33, 0x0200000500402000ull, "b.anynaq lri" },
{ 33, 0x0216fe167301c8c0ull, "bu.anya zero_addr+0x7316fe10, rf35" },
{ 33, 0x020000050040e000ull, "bu.anynaq lri, r:unif" },
{ 33, 0x0200000300006000ull, "bu.na0 lri, a:unif" },
/* Special waddr names */
{ 33, 0x3c00318735808000ull, "vfpack tlb, r0, r1 ; nop" },
{ 33, 0xe0571c938e8d5000ull, "fmax.andc recip, r5.h, r2.l; fmul.ifb rf50.h, r3.l, r4.abs; ldunif" },
{ 33, 0xc04098d4382c9000ull, "add.pushn rsqrt, r1, r1; fmul rf35.h, r3.abs, r1.abs; ldunif" },
{ 33, 0x481edcd6b3184500ull, "vfmin.norn log, r4.hh, r0; fmul.ifnb rf51, rf20.abs, r0.l" },
{ 33, 0x041618d57c453000ull, "shl.andn exp, r3, r2; add.ifb rf35, r1, r2" },
{ 33, 0x7048e5da49272800ull, "fsub.ifa rf26, r2.l, rf32; fmul.pushc sin, r1.h, r1.abs; ldunif" },
};
static void
swap_mux(enum v3d_qpu_mux *a, enum v3d_qpu_mux *b)
{
enum v3d_qpu_mux t = *a;
*a = *b;
*b = t;
}
static void
swap_pack(enum v3d_qpu_input_unpack *a, enum v3d_qpu_input_unpack *b)
{
enum v3d_qpu_input_unpack t = *a;
*a = *b;
*b = t;
}
int
main(int argc, char **argv)
{
struct v3d_device_info devinfo = { };
int retval = 0;
for (int i = 0; i < ARRAY_SIZE(tests); i++) {
devinfo.ver = tests[i].ver;
printf("Testing v%d.%d 0x%016llx... ",
devinfo.ver / 10, devinfo.ver % 10,
(long long)tests[i].inst);
const char *disasm_output = v3d_qpu_disasm(&devinfo,
tests[i].inst);
if (strcmp(disasm_output, tests[i].expected) != 0) {
printf("FAIL\n");
printf(" Expected: \"%s\"\n", tests[i].expected);
printf(" Got: \"%s\"\n", disasm_output);
retval = 1;
continue;
}
struct v3d_qpu_instr instr;
if (!v3d_qpu_instr_unpack(&devinfo, tests[i].inst, &instr)) {
printf("FAIL (unpack) %s\n", tests[i].expected);
retval = 1;
continue;
}
if (instr.type == V3D_QPU_INSTR_TYPE_ALU) {
switch (instr.alu.add.op) {
case V3D_QPU_A_FADD:
case V3D_QPU_A_FADDNF:
case V3D_QPU_A_FMIN:
case V3D_QPU_A_FMAX:
/* Swap the operands to be sure that we test
* how the QPUs distinguish between these ops.
*/
swap_mux(&instr.alu.add.a,
&instr.alu.add.b);
swap_pack(&instr.alu.add.a_unpack,
&instr.alu.add.b_unpack);
default:
break;
}
}
uint64_t repack;
if (!v3d_qpu_instr_pack(&devinfo, &instr, &repack)) {
printf("FAIL (pack) %s\n", tests[i].expected);
retval = 1;
continue;
}
if (repack != tests[i].inst) {
printf("FAIL (repack) 0x%016llx\n", (long long)repack);
printf(" Expected: \"%s\"\n", tests[i].expected);
const char *redisasm = v3d_qpu_disasm(&devinfo, repack);
printf(" Got: \"%s\"\n", redisasm);
retval = 1;
}
printf("PASS\n");
}
return retval;
}