Path: blob/21.2-virgl/src/broadcom/qpu/qpu_disasm.c
4560 views
/*1* Copyright © 2016 Broadcom2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING19* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS20* IN THE SOFTWARE.21*/2223#include <string.h>24#include <stdio.h>25#include "util/ralloc.h"2627#include "broadcom/common/v3d_device_info.h"28#include "qpu_instr.h"29#include "qpu_disasm.h"3031struct disasm_state {32const struct v3d_device_info *devinfo;33char *string;34size_t offset;35};3637static void38append(struct disasm_state *disasm, const char *fmt, ...)39{40va_list args;41va_start(args, fmt);42ralloc_vasprintf_rewrite_tail(&disasm->string,43&disasm->offset,44fmt, args);45va_end(args);46}4748static void49pad_to(struct disasm_state *disasm, int n)50{51/* FIXME: Do a single append somehow. */52while (disasm->offset < n)53append(disasm, " ");54}555657static void58v3d_qpu_disasm_raddr(struct disasm_state *disasm,59const struct v3d_qpu_instr *instr, uint8_t mux)60{61if (mux == V3D_QPU_MUX_A) {62append(disasm, "rf%d", instr->raddr_a);63} else if (mux == V3D_QPU_MUX_B) {64if (instr->sig.small_imm) {65uint32_t val;66ASSERTED bool ok =67v3d_qpu_small_imm_unpack(disasm->devinfo,68instr->raddr_b,69&val);7071if ((int)val >= -16 && (int)val <= 15)72append(disasm, "%d", val);73else74append(disasm, "0x%08x", val);75assert(ok);76} else {77append(disasm, "rf%d", instr->raddr_b);78}79} else {80append(disasm, "r%d", mux);81}82}8384static void85v3d_qpu_disasm_waddr(struct disasm_state *disasm, uint32_t waddr, bool magic)86{87if (!magic) {88append(disasm, "rf%d", waddr);89return;90}9192const char *name = v3d_qpu_magic_waddr_name(disasm->devinfo, waddr);93if (name)94append(disasm, "%s", name);95else96append(disasm, "waddr UNKNOWN %d", waddr);97}9899static void100v3d_qpu_disasm_add(struct disasm_state *disasm,101const struct v3d_qpu_instr *instr)102{103bool has_dst = v3d_qpu_add_op_has_dst(instr->alu.add.op);104int num_src = v3d_qpu_add_op_num_src(instr->alu.add.op);105106append(disasm, "%s", v3d_qpu_add_op_name(instr->alu.add.op));107if (!v3d_qpu_sig_writes_address(disasm->devinfo, &instr->sig))108append(disasm, "%s", v3d_qpu_cond_name(instr->flags.ac));109append(disasm, "%s", v3d_qpu_pf_name(instr->flags.apf));110append(disasm, "%s", v3d_qpu_uf_name(instr->flags.auf));111112append(disasm, " ");113114if (has_dst) {115v3d_qpu_disasm_waddr(disasm, instr->alu.add.waddr,116instr->alu.add.magic_write);117append(disasm, v3d_qpu_pack_name(instr->alu.add.output_pack));118}119120if (num_src >= 1) {121if (has_dst)122append(disasm, ", ");123v3d_qpu_disasm_raddr(disasm, instr, instr->alu.add.a);124append(disasm, "%s",125v3d_qpu_unpack_name(instr->alu.add.a_unpack));126}127128if (num_src >= 2) {129append(disasm, ", ");130v3d_qpu_disasm_raddr(disasm, instr, instr->alu.add.b);131append(disasm, "%s",132v3d_qpu_unpack_name(instr->alu.add.b_unpack));133}134}135136static void137v3d_qpu_disasm_mul(struct disasm_state *disasm,138const struct v3d_qpu_instr *instr)139{140bool has_dst = v3d_qpu_mul_op_has_dst(instr->alu.mul.op);141int num_src = v3d_qpu_mul_op_num_src(instr->alu.mul.op);142143pad_to(disasm, 21);144append(disasm, "; ");145146append(disasm, "%s", v3d_qpu_mul_op_name(instr->alu.mul.op));147if (!v3d_qpu_sig_writes_address(disasm->devinfo, &instr->sig))148append(disasm, "%s", v3d_qpu_cond_name(instr->flags.mc));149append(disasm, "%s", v3d_qpu_pf_name(instr->flags.mpf));150append(disasm, "%s", v3d_qpu_uf_name(instr->flags.muf));151152if (instr->alu.mul.op == V3D_QPU_M_NOP)153return;154155append(disasm, " ");156157if (has_dst) {158v3d_qpu_disasm_waddr(disasm, instr->alu.mul.waddr,159instr->alu.mul.magic_write);160append(disasm, v3d_qpu_pack_name(instr->alu.mul.output_pack));161}162163if (num_src >= 1) {164if (has_dst)165append(disasm, ", ");166v3d_qpu_disasm_raddr(disasm, instr, instr->alu.mul.a);167append(disasm, "%s",168v3d_qpu_unpack_name(instr->alu.mul.a_unpack));169}170171if (num_src >= 2) {172append(disasm, ", ");173v3d_qpu_disasm_raddr(disasm, instr, instr->alu.mul.b);174append(disasm, "%s",175v3d_qpu_unpack_name(instr->alu.mul.b_unpack));176}177}178179static void180v3d_qpu_disasm_sig_addr(struct disasm_state *disasm,181const struct v3d_qpu_instr *instr)182{183if (disasm->devinfo->ver < 41)184return;185186if (!instr->sig_magic)187append(disasm, ".rf%d", instr->sig_addr);188else {189const char *name =190v3d_qpu_magic_waddr_name(disasm->devinfo,191instr->sig_addr);192if (name)193append(disasm, ".%s", name);194else195append(disasm, ".UNKNOWN%d", instr->sig_addr);196}197}198199static void200v3d_qpu_disasm_sig(struct disasm_state *disasm,201const struct v3d_qpu_instr *instr)202{203const struct v3d_qpu_sig *sig = &instr->sig;204205if (!sig->thrsw &&206!sig->ldvary &&207!sig->ldvpm &&208!sig->ldtmu &&209!sig->ldtlb &&210!sig->ldtlbu &&211!sig->ldunif &&212!sig->ldunifrf &&213!sig->ldunifa &&214!sig->ldunifarf &&215!sig->wrtmuc) {216return;217}218219pad_to(disasm, 41);220221if (sig->thrsw)222append(disasm, "; thrsw");223if (sig->ldvary) {224append(disasm, "; ldvary");225v3d_qpu_disasm_sig_addr(disasm, instr);226}227if (sig->ldvpm)228append(disasm, "; ldvpm");229if (sig->ldtmu) {230append(disasm, "; ldtmu");231v3d_qpu_disasm_sig_addr(disasm, instr);232}233if (sig->ldtlb) {234append(disasm, "; ldtlb");235v3d_qpu_disasm_sig_addr(disasm, instr);236}237if (sig->ldtlbu) {238append(disasm, "; ldtlbu");239v3d_qpu_disasm_sig_addr(disasm, instr);240}241if (sig->ldunif)242append(disasm, "; ldunif");243if (sig->ldunifrf) {244append(disasm, "; ldunifrf");245v3d_qpu_disasm_sig_addr(disasm, instr);246}247if (sig->ldunifa)248append(disasm, "; ldunifa");249if (sig->ldunifarf) {250append(disasm, "; ldunifarf");251v3d_qpu_disasm_sig_addr(disasm, instr);252}253if (sig->wrtmuc)254append(disasm, "; wrtmuc");255}256257static void258v3d_qpu_disasm_alu(struct disasm_state *disasm,259const struct v3d_qpu_instr *instr)260{261v3d_qpu_disasm_add(disasm, instr);262v3d_qpu_disasm_mul(disasm, instr);263v3d_qpu_disasm_sig(disasm, instr);264}265266static void267v3d_qpu_disasm_branch(struct disasm_state *disasm,268const struct v3d_qpu_instr *instr)269{270append(disasm, "b");271if (instr->branch.ub)272append(disasm, "u");273append(disasm, "%s", v3d_qpu_branch_cond_name(instr->branch.cond));274append(disasm, "%s", v3d_qpu_msfign_name(instr->branch.msfign));275276switch (instr->branch.bdi) {277case V3D_QPU_BRANCH_DEST_ABS:278append(disasm, " zero_addr+0x%08x", instr->branch.offset);279break;280281case V3D_QPU_BRANCH_DEST_REL:282append(disasm, " %d", instr->branch.offset);283break;284285case V3D_QPU_BRANCH_DEST_LINK_REG:286append(disasm, " lri");287break;288289case V3D_QPU_BRANCH_DEST_REGFILE:290append(disasm, " rf%d", instr->branch.raddr_a);291break;292}293294if (instr->branch.ub) {295switch (instr->branch.bdu) {296case V3D_QPU_BRANCH_DEST_ABS:297append(disasm, ", a:unif");298break;299300case V3D_QPU_BRANCH_DEST_REL:301append(disasm, ", r:unif");302break;303304case V3D_QPU_BRANCH_DEST_LINK_REG:305append(disasm, ", lri");306break;307308case V3D_QPU_BRANCH_DEST_REGFILE:309append(disasm, ", rf%d", instr->branch.raddr_a);310break;311}312}313}314315const char *316v3d_qpu_decode(const struct v3d_device_info *devinfo,317const struct v3d_qpu_instr *instr)318{319struct disasm_state disasm = {320.string = rzalloc_size(NULL, 1),321.offset = 0,322.devinfo = devinfo,323};324325switch (instr->type) {326case V3D_QPU_INSTR_TYPE_ALU:327v3d_qpu_disasm_alu(&disasm, instr);328break;329330case V3D_QPU_INSTR_TYPE_BRANCH:331v3d_qpu_disasm_branch(&disasm, instr);332break;333}334335return disasm.string;336}337338/**339* Returns a string containing the disassembled representation of the QPU340* instruction. It is the caller's responsibility to free the return value341* with ralloc_free().342*/343const char *344v3d_qpu_disasm(const struct v3d_device_info *devinfo, uint64_t inst)345{346struct v3d_qpu_instr instr;347bool ok = v3d_qpu_instr_unpack(devinfo, inst, &instr);348assert(ok); (void)ok;349350return v3d_qpu_decode(devinfo, &instr);351}352353void354v3d_qpu_dump(const struct v3d_device_info *devinfo,355const struct v3d_qpu_instr *instr)356{357const char *decoded = v3d_qpu_decode(devinfo, instr);358fprintf(stderr, "%s", decoded);359ralloc_free((char *)decoded);360}361362363