[Mesa-dev] [PATCH 1/2] aubinator: Add a new tool called Aubinator to the src/intel/tools folder.
Matt Turner
mattst88 at gmail.com
Wed Aug 10 21:24:14 UTC 2016
On Tue, Aug 9, 2016 at 4:52 PM, Sirisha Gandikota
<sirisha.gandikota at intel.com> wrote:
> From: Kristian Høgsberg Kristensen <krh at bitplanet.net>
>
> The Aubinator tool is designed to help the driver developers in debugging
> the driver functionality by decoding the data in the .aub files.
> Primary Authors of this tool are Damien Lespiau <damien.lespiau at intel.com>
> and Kristian Høgsberg Kristensen <krh at bitplanet.net>.
>
> Signed-off-by: Sirisha Gandikota <Sirisha.Gandikota at intel.com>
> ---
> configure.ac | 1 +
> src/Makefile.am | 4 +
> src/intel/tools/Makefile.am | 65 +++
> src/intel/tools/aubinator.c | 1039 ++++++++++++++++++++++++++++++++++++++++++
> src/intel/tools/decoder.c | 520 +++++++++++++++++++++
> src/intel/tools/decoder.h | 57 +++
> src/intel/tools/disasm.c | 109 +++++
> src/intel/tools/gen_disasm.h | 35 ++
> src/intel/tools/intel_aub.h | 154 +++++++
> 9 files changed, 1984 insertions(+)
> create mode 100644 src/intel/tools/Makefile.am
> create mode 100644 src/intel/tools/aubinator.c
> create mode 100644 src/intel/tools/decoder.c
> create mode 100644 src/intel/tools/decoder.h
> create mode 100644 src/intel/tools/disasm.c
> create mode 100644 src/intel/tools/gen_disasm.h
> create mode 100644 src/intel/tools/intel_aub.h
>
> diff --git a/configure.ac b/configure.ac
> index aea5890..acc8356 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -2742,6 +2742,7 @@ AC_CONFIG_FILES([Makefile
> src/intel/genxml/Makefile
> src/intel/isl/Makefile
> src/intel/vulkan/Makefile
> + src/intel/tools/Makefile
This list is alphabetical. tools before vulkan.
> src/loader/Makefile
> src/mapi/Makefile
> src/mapi/es1api/glesv1_cm.pc
> diff --git a/src/Makefile.am b/src/Makefile.am
> index d4e34b4..190ad08 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -88,6 +88,10 @@ if HAVE_INTEL_VULKAN
> SUBDIRS += intel/vulkan
> endif
>
> +if HAVE_INTEL_DRIVERS
> +SUBDIRS += intel/tools
> +endif
> +
> if HAVE_GALLIUM
> SUBDIRS += gallium
> endif
> diff --git a/src/intel/tools/Makefile.am b/src/intel/tools/Makefile.am
> new file mode 100644
> index 0000000..cf5477f
> --- /dev/null
> +++ b/src/intel/tools/Makefile.am
> @@ -0,0 +1,65 @@
> +# Copyright © 2016 Intel Corporation
> +#
> +# 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.
> +
> +CLEANFILES = \
> + aubinator-aubinator.o \
> + aubinator-decoder.o \
> + disasm.lo \
> + libdisasm.la
> +
> +noinst_LTLIBRARIES = libdisasm.la
> +
> +AM_CPPFLAGS = \
> + $(INTEL_CFLAGS) \
> + $(VALGRIND_CFLAGS) \
> + $(DEFINES) \
> + -I$(top_srcdir)/include \
> + -I$(top_builddir)/src \
> + -I$(top_srcdir)/src \
> + -I$(top_builddir)/src/compiler \
> + -I$(top_srcdir)/src/compiler \
> + -I$(top_builddir)/src/compiler/nir \
> + -I$(top_srcdir)/src/mapi \
> + -I$(top_srcdir)/src/mesa \
> + -I$(top_srcdir)/src/mesa/drivers/dri/common \
> + -I$(top_srcdir)/src/mesa/drivers/dri/i965 \
> + -I$(top_srcdir)/src/gallium/auxiliary \
> + -I$(top_srcdir)/src/gallium/include \
> + -I$(top_builddir)/src/intel \
> + -I$(top_srcdir)/src/intel
> +
> +libdisasm_la_SOURCES = \
> + gen_disasm.h \
> + disasm.c
> +libdisasm_la_LIBADD = $(top_builddir)/src/mesa/drivers/dri/i965/libi965_compiler.la \
> + $(top_builddir)/src/mesa/libmesa.la \
> + $(PER_GEN_LIBS) \
> + $(PTHREAD_LIBS) \
> + $(DLOPEN_LIBS) \
> + -lm
> +
> +
> +bin_PROGRAMS = aubinator
Point of discussion: do we actually want to install this to the users' systems?
> +
> +aubinator_SOURCES = intel_aub.h decoder.c decoder.h aubinator.c
> +aubinator_CFLAGS = $(EXPAT_CFLAGS) $(AM_CFLAGS) -I$(top_srcdir)/src -I$(top_srcdir)/include
> +
> +aubinator_LDADD = $(EXPAT_LIBS) libdisasm.la
> diff --git a/src/intel/tools/aubinator.c b/src/intel/tools/aubinator.c
> new file mode 100644
> index 0000000..99d67a1
> --- /dev/null
> +++ b/src/intel/tools/aubinator.c
> @@ -0,0 +1,1039 @@
> +/*
> + * Copyright © 2016 Intel Corporation
> + *
> + * 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.
> + */
> +
> +#define _GNU_SOURCE
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <stdint.h>
> +
> +#include <unistd.h>
> +#include <fcntl.h>
> +#include <string.h>
> +#include <signal.h>
> +#include <errno.h>
> +#include <error.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <sys/wait.h>
> +#include <sys/mman.h>
> +
> +#include "decoder.h"
> +#include "intel_aub.h"
> +#include "gen_disasm.h"
> +
> +#define CSI "\e["
> +#define HEADER CSI "37;44m"
> +#define NORMAL CSI "0m"
> +#define CLEAR_TO_EOL CSI "0K"
> +
> +/* options */
> +
> +static bool option_full_decode = true;
> +static bool option_print_offsets = true;
> +static enum { COLOR_AUTO, COLOR_ALWAYS, COLOR_NEVER } option_color;
> +
> +/* state */
> +
> +struct gen_disasm *disasm;
> +
> +uint64_t gtt_size, gtt_end;
> +void *gtt;
> +uint64_t general_state_base;
> +uint64_t surface_state_base;
> +uint64_t dynamic_state_base;
> +uint64_t instruction_base;
> +uint64_t instruction_bound;
> +
> +static inline uint32_t
> +field(uint32_t value, int start, int end)
> +{
> + uint32_t mask;
> +
> + mask = ~0U >> (31 - end + start);
> +
> + return (value >> start) & mask;
> +}
> +
> +struct brw_instruction;
> +
> +static inline int
> +valid_offset(uint32_t offset)
> +{
> + return offset < gtt_end;
> +}
> +
> +static void
> +decode_structure(struct gen_spec *spec, struct gen_group *strct, const uint32_t *p)
> +{
> + struct gen_field_iterator iter;
> +
> + gen_field_iterator_init(&iter, strct, p);
> + while (gen_field_iterator_next(&iter)) {
> + printf(" %s: %s\n", iter.name, iter.value);
> + }
> +}
> +
> +static void
> +dump_binding_table(struct gen_spec *spec, uint32_t offset)
> +{
> + uint32_t *pointers, i;
> + uint64_t start;
> + struct gen_group *surface_state;
> +
> + surface_state = gen_spec_find_struct(spec, "RENDER_SURFACE_STATE");
> + if (surface_state == NULL) {
> + printf("did not find RENDER_SURFACE_STATE info\n");
> + return;
> + }
> +
> + start = surface_state_base + offset;
> + pointers = gtt + start;
> + for (i = 0; i < 16; i++) {
> + if (pointers[i] == 0)
> + continue;
> + start = pointers[i] + surface_state_base;
> + if (!valid_offset(start)) {
> + printf("pointer %u: %08x <not valid>\n",
> + i, pointers[i]);
> + continue;
> + } else {
> + printf("pointer %u: %08x\n", i, pointers[i]);
> + }
> +
> + decode_structure(spec, surface_state, gtt + start);
> + }
> +}
> +
> +static void
> +handle_3dstate_index_buffer(struct gen_spec *spec, uint32_t *p)
> +{
> + void *start;
> + uint32_t length, i, type, size;
> +
> + start = gtt + p[2];
> + type = (p[1] >> 8) & 3;
> + size = 1 << type;
> + length = p[4] / size;
> + if (length > 10)
> + length = 10;
> +
> + printf("\t");
> +
> + for (i = 0; i < length; i++) {
> + switch (type) {
> + case 0:
> + printf("%3d ", ((uint8_t *)start)[i]);
> + break;
> + case 1:
> + printf("%3d ", ((uint16_t *)start)[i]);
> + break;
> + case 2:
> + printf("%3d ", ((uint32_t *)start)[i]);
> + break;
> + }
> + }
> + if (length < p[4] / size)
> + printf("...\n");
> + else
> + printf("\n");
> +}
> +
> +static inline uint64_t
> +get_qword(uint32_t *p)
> +{
> + return ((uint64_t) p[1] << 32) | p[0];
> +}
> +
> +static void
> +handle_state_base_address(struct gen_spec *spec, uint32_t *p)
> +{
> + uint64_t mask = ~((1 << 12) - 1);
> +
> + if (gen_spec_get_gen(spec) >= gen_make_gen(8,0)) {
> + if (p[1] & 1)
> + general_state_base = get_qword(&p[1]) & mask;
> + if (p[4] & 1)
> + surface_state_base = get_qword(&p[4]) & mask;
> + if (p[6] & 1)
> + dynamic_state_base = get_qword(&p[6]) & mask;
> + if (p[10] & 1)
> + instruction_base = get_qword(&p[10]) & mask;
> + if (p[15] & 1)
> + instruction_bound = p[15] & mask;
> + } else {
> + if (p[2] & 1)
> + surface_state_base = p[2] & mask;
> + if (p[3] & 1)
> + dynamic_state_base = p[3] & mask;
> + if (p[5] & 1)
> + instruction_base = p[5] & mask;
> + if (p[9] & 1)
> + instruction_bound = p[9] & mask;
> + }
> +}
> +
> +static void
> +dump_samplers(struct gen_spec *spec, uint32_t offset)
> +{
> + uint32_t i;
> + uint64_t start;
> + struct gen_group *sampler_state;
> +
> + sampler_state = gen_spec_find_struct(spec, "SAMPLER_STATE");
> +
> + start = dynamic_state_base + offset;
> + for (i = 0; i < 4; i++) {
> + printf("sampler state %d\n", i);
> + decode_structure(spec, sampler_state, gtt + start + i * 16);
> + }
> +}
> +
> +static void
> +handle_media_interface_descriptor_load(struct gen_spec *spec, uint32_t *p)
> +{
> + int i, length = p[2] / 32;
> + struct gen_group *descriptor_structure;
> + uint32_t *descriptors;
> + uint64_t start;
> + struct brw_instruction *insns;
> +
> + descriptor_structure =
> + gen_spec_find_struct(spec, "INTERFACE_DESCRIPTOR_DATA");
> + if (descriptor_structure == NULL) {
> + printf("did not find INTERFACE_DESCRIPTOR_DATA info\n");
> + return;
> + }
> +
> + start = dynamic_state_base + p[3];
> + descriptors = gtt + start;
> + for (i = 0; i < length; i++, descriptors += 8) {
> + printf("descriptor %u: %08x\n", i, *descriptors);
> + decode_structure(spec, descriptor_structure, descriptors);
> +
> + start = instruction_base + descriptors[0];
> + if (!valid_offset(start)) {
> + printf("kernel: %08lx <not valid>\n", start);
> + continue;
> + } else {
> + printf("kernel: %08lx\n", start);
> + }
> +
> + insns = (struct brw_instruction *) (gtt + start);
> + gen_disasm_disassemble(disasm, insns, 0, 8192, stdout);
> +
> + dump_samplers(spec, descriptors[3] & ~0x1f);
> + dump_binding_table(spec, descriptors[4] & ~0x1f);
> + }
> +}
> +
> +/* Heuristic to determine whether a uint32_t is probably actually a float
> + * (http://stackoverflow.com/a/2953466) */
> +
> +static bool
> +probably_float(uint32_t bits)
> +{
> + int exp = ((bits & 0x7f800000U) >> 23) - 127;
> + uint32_t mant = bits & 0x007fffff;
> +
> + // +- 0.0
> + if (exp == -127 && mant == 0)
> + return true;
> +
> + // +- 1 billionth to 1 billion
> + if (-30 <= exp && exp <= 30)
> + return true;
> +
> + // some value with only a few binary digits
> + if ((mant & 0x0000ffff) == 0)
> + return true;
> +
> + return false;
> +}
> +
> +static void
> +handle_3dstate_vertex_buffers(struct gen_spec *spec, uint32_t *p)
> +{
> + uint32_t *end, *s, *dw, *dwend;
> + uint64_t offset;
> + int n, i, count, stride;
> +
> + end = (p[0] & 0xff) + p + 2;
> + for (s = &p[1], n = 0; s < end; s += 4, n++) {
> + if (gen_spec_get_gen(spec) >= gen_make_gen(8, 0)) {
> + offset = *(uint64_t *) &s[1];
> + dwend = gtt + offset + s[3];
> + } else {
> + offset = s[1];
> + dwend = gtt + s[2] + 1;
> + }
> +
> + stride = field(s[0], 0, 11);
> + count = 0;
> + printf("vertex buffer %d, size %d\n", n, s[3]);
> + for (dw = gtt + offset, i = 0; dw < dwend && i < 256; dw++) {
> + if (count == 0 && count % (8 * 4) == 0)
> + printf(" ");
> +
> + if (probably_float(*dw))
> + printf(" %8.2f", *(float *) dw);
> + else
> + printf(" 0x%08x", *dw);
> +
> + i++;
> + count += 4;
> +
> + if (count == stride) {
> + printf("\n");
> + count = 0;
> + } else if (count % (8 * 4) == 0) {
> + printf("\n");
> + } else {
> + printf(" ");
> + }
> + }
> + if (count > 0 && count % (8 * 4) != 0)
> + printf("\n");
> + }
> +}
> +
> +static void
> +handle_3dstate_vs(struct gen_spec *spec, uint32_t *p)
> +{
> + uint64_t start;
> + struct brw_instruction *insns;
> + int vs_enable;
> +
> + if (gen_spec_get_gen(spec) >= gen_make_gen(8, 0)) {
> + start = get_qword(&p[1]);
> + vs_enable = p[7] & 1;
> + } else {
> + start = p[1];
> + vs_enable = p[5] & 1;
> + }
> +
> + if (vs_enable) {
> + printf("instruction_base %08lx, start %08lx\n",
> + instruction_base, start);
> +
> + insns = (struct brw_instruction *) (gtt + instruction_base + start);
> + gen_disasm_disassemble(disasm, insns, 0, 8192, stdout);
> + }
> +}
> +
> +static void
> +handle_3dstate_constant(struct gen_spec *spec, uint32_t *p)
> +{
> + int i, j, length;
> + uint32_t *dw;
> + float *f;
> +
> + for (i = 0; i < 4; i++) {
> + length = (p[1 + i / 2] >> (i & 1) * 16) & 0xffff;
> + f = (float *) (gtt + p[3 + i * 2] + dynamic_state_base);
> + dw = (uint32_t *) f;
> + for (j = 0; j < length * 8; j++) {
> + if (probably_float(dw[j]))
> + printf(" %04.3f", f[j]);
> + else
> + printf(" 0x%08x", dw[j]);
> +
> + if ((j & 7) == 7)
> + printf("\n");
> + }
> + }
> +}
> +
> +static void
> +handle_3dstate_ps(struct gen_spec *spec, uint32_t *p)
> +{
> + uint32_t mask = ~((1 << 6) - 1);
> + uint64_t start;
> + struct brw_instruction *insns;
> + static const char unused[] = "unused";
> + const char *k0, *k1, *k2;
> + uint32_t k_mask, k1_offset, k2_offset;
> +
> + if (gen_spec_get_gen(spec) >= gen_make_gen(8, 0)) {
> + k_mask = p[6] & 7;
> + k1_offset = 8;
> + k2_offset = 10;
> + } else {
> + k_mask = p[4] & 7;
> + k1_offset = 6;
> + k2_offset = 7;
> + }
> +
> +#define DISPATCH_8 1
> +#define DISPATCH_16 2
> +#define DISPATCH_32 4
> +
> + switch (k_mask) {
> + case DISPATCH_8:
> + k0 = "8 pixel";
> + k1 = unused;
> + k2 = unused;
> + break;
> + case DISPATCH_16:
> + k0 = "16 pixel";
> + k1 = unused;
> + k2 = unused;
> + break;
> + case DISPATCH_8 | DISPATCH_16:
> + k0 = "8 pixel";
> + k1 = unused;
> + k2 = "16 pixel";
> + break;
> + case DISPATCH_32:
> + k0 = "32 pixel";
> + k1 = unused;
> + k2 = unused;
> + break;
> + case DISPATCH_16 | DISPATCH_32:
> + k0 = unused;
> + k1 = "32 pixel";
> + k2 = "16 pixel";
> + break;
> + case DISPATCH_8 | DISPATCH_16 | DISPATCH_32:
> + k0 = "8 pixel";
> + k1 = "32 pixel";
> + k2 = "16 pixel";
> + break;
> + default:
> + k0 = unused;
> + k1 = unused;
> + k2 = unused;
> + break;
> + }
> +
> + start = instruction_base + (p[1] & mask);
> + printf(" Kernel[0] %s\n", k0);
> + if (k0 != unused) {
> + insns = (struct brw_instruction *) (gtt + start);
> + gen_disasm_disassemble(disasm, insns, 0, 8192, stdout);
> + }
> +
> + start = instruction_base + (p[k1_offset] & mask);
> + printf(" Kernel[1] %s\n", k1);
> + if (k1 != unused) {
> + insns = (struct brw_instruction *) (gtt + start);
> + gen_disasm_disassemble(disasm, insns, 0, 8192, stdout);
> + }
> +
> + start = instruction_base + (p[k2_offset] & mask);
> + printf(" Kernel[2] %s\n", k2);
> + if (k2 != unused) {
> + insns = (struct brw_instruction *) (gtt + start);
> + gen_disasm_disassemble(disasm, insns, 0, 8192, stdout);
> + }
> +}
> +
> +static void
> +handle_3dstate_binding_table_pointers(struct gen_spec *spec, uint32_t *p)
> +{
> + dump_binding_table(spec, p[1]);
> +}
> +
> +static void
> +handle_3dstate_sampler_state_pointers(struct gen_spec *spec, uint32_t *p)
> +{
> + dump_samplers(spec, p[1]);
> +}
> +
> +static void
> +handle_3dstate_viewport_state_pointers_cc(struct gen_spec *spec, uint32_t *p)
> +{
> + uint64_t start;
> + struct gen_group *cc_viewport;
> +
> + cc_viewport = gen_spec_find_struct(spec, "CC_VIEWPORT");
> +
> + start = dynamic_state_base + (p[1] & ~0x1fu);
> + for (uint32_t i = 0; i < 4; i++) {
> + printf("viewport %d\n", i);
> + decode_structure(spec, cc_viewport, gtt + start + i * 8);
> + }
> +}
> +
> +static void
> +handle_3dstate_viewport_state_pointers_sf_clip(struct gen_spec *spec, uint32_t *p)
> +{
> + uint64_t start;
> + struct gen_group *sf_clip_viewport;
> +
> + sf_clip_viewport = gen_spec_find_struct(spec, "SF_CLIP_VIEWPORT");
> +
> + start = dynamic_state_base + (p[1] & ~0x3fu);
> + for (uint32_t i = 0; i < 4; i++) {
> + printf("viewport %d\n", i);
> + decode_structure(spec, sf_clip_viewport, gtt + start + i * 64);
> + }
> +}
> +
> +static void
> +handle_3dstate_blend_state_pointers(struct gen_spec *spec, uint32_t *p)
> +{
> + uint64_t start;
> + struct gen_group *blend_state;
> +
> + blend_state = gen_spec_find_struct(spec, "BLEND_STATE");
> +
> + start = dynamic_state_base + (p[1] & ~0x3fu);
> + decode_structure(spec, blend_state, gtt + start);
> +}
> +
> +static void
> +handle_3dstate_cc_state_pointers(struct gen_spec *spec, uint32_t *p)
> +{
> + uint64_t start;
> + struct gen_group *cc_state;
> +
> + cc_state = gen_spec_find_struct(spec, "COLOR_CALC_STATE");
> +
> + start = dynamic_state_base + (p[1] & ~0x3fu);
> + decode_structure(spec, cc_state, gtt + start);
> +}
> +
> +static void
> +handle_3dstate_scissor_state_pointers(struct gen_spec *spec, uint32_t *p)
> +{
> + uint64_t start;
> + struct gen_group *scissor_rect;
> +
> + scissor_rect = gen_spec_find_struct(spec, "SCISSOR_RECT");
> +
> + start = dynamic_state_base + (p[1] & ~0x1fu);
> + decode_structure(spec, scissor_rect, gtt + start);
> +}
> +
> +#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
> +
> +#define STATE_BASE_ADDRESS 0x61010000
> +
> +#define MEDIA_INTERFACE_DESCRIPTOR_LOAD 0x70020000
> +
> +#define _3DSTATE_INDEX_BUFFER 0x780a0000
> +#define _3DSTATE_VERTEX_BUFFERS 0x78080000
> +
> +#define _3DSTATE_VS 0x78100000
> +#define _3DSTATE_GS 0x78110000
> +
> +#define _3DSTATE_CONSTANT_VS 0x78150000
> +#define _3DSTATE_CONSTANT_GS 0x78160000
> +#define _3DSTATE_CONSTANT_PS 0x78170000
> +#define _3DSTATE_CONSTANT_HS 0x78190000
> +#define _3DSTATE_CONSTANT_DS 0x781A0000
> +
> +#define _3DSTATE_PS 0x78200000
> +
> +#define _3DSTATE_BINDING_TABLE_POINTERS_VS 0x78260000
> +#define _3DSTATE_BINDING_TABLE_POINTERS_HS 0x78270000
> +#define _3DSTATE_BINDING_TABLE_POINTERS_DS 0x78280000
> +#define _3DSTATE_BINDING_TABLE_POINTERS_GS 0x78290000
> +#define _3DSTATE_BINDING_TABLE_POINTERS_PS 0x782a0000
> +
> +#define _3DSTATE_SAMPLER_STATE_POINTERS_VS 0x782b0000
> +#define _3DSTATE_SAMPLER_STATE_POINTERS_GS 0x782e0000
> +#define _3DSTATE_SAMPLER_STATE_POINTERS_PS 0x782f0000
> +
> +#define _3DSTATE_VIEWPORT_STATE_POINTERS_CC 0x78230000
> +#define _3DSTATE_VIEWPORT_STATE_POINTERS_SF_CLIP 0x78210000
> +#define _3DSTATE_BLEND_STATE_POINTERS 0x78240000
> +#define _3DSTATE_CC_STATE_POINTERS 0x780e0000
> +#define _3DSTATE_SCISSOR_STATE_POINTERS 0x780f0000
> +
> +struct custom_handler {
> + uint32_t opcode;
> + void (*handle)(struct gen_spec *spec, uint32_t *p);
> +} custom_handlers[] = {
> + { STATE_BASE_ADDRESS, handle_state_base_address },
> + { MEDIA_INTERFACE_DESCRIPTOR_LOAD, handle_media_interface_descriptor_load },
> + { _3DSTATE_VERTEX_BUFFERS, handle_3dstate_vertex_buffers },
> + { _3DSTATE_INDEX_BUFFER, handle_3dstate_index_buffer },
> + { _3DSTATE_VS, handle_3dstate_vs },
> + { _3DSTATE_GS, handle_3dstate_vs },
> + /* FIXME: Handle disassmbing for 3DSTATE_HS and 3DSTATE_DS. */
> + { _3DSTATE_CONSTANT_VS, handle_3dstate_constant },
> + { _3DSTATE_CONSTANT_GS, handle_3dstate_constant },
> + { _3DSTATE_CONSTANT_PS, handle_3dstate_constant },
> + { _3DSTATE_CONSTANT_HS, handle_3dstate_constant },
> + { _3DSTATE_CONSTANT_DS, handle_3dstate_constant },
> + { _3DSTATE_PS, handle_3dstate_ps },
> +
> + { _3DSTATE_BINDING_TABLE_POINTERS_VS, handle_3dstate_binding_table_pointers },
> + { _3DSTATE_BINDING_TABLE_POINTERS_HS, handle_3dstate_binding_table_pointers },
> + { _3DSTATE_BINDING_TABLE_POINTERS_DS, handle_3dstate_binding_table_pointers },
> + { _3DSTATE_BINDING_TABLE_POINTERS_GS, handle_3dstate_binding_table_pointers },
> + { _3DSTATE_BINDING_TABLE_POINTERS_PS, handle_3dstate_binding_table_pointers },
> +
> + { _3DSTATE_SAMPLER_STATE_POINTERS_VS, handle_3dstate_sampler_state_pointers },
> + { _3DSTATE_SAMPLER_STATE_POINTERS_GS, handle_3dstate_sampler_state_pointers },
> + { _3DSTATE_SAMPLER_STATE_POINTERS_PS, handle_3dstate_sampler_state_pointers },
> +
> + { _3DSTATE_VIEWPORT_STATE_POINTERS_CC, handle_3dstate_viewport_state_pointers_cc },
> + { _3DSTATE_VIEWPORT_STATE_POINTERS_SF_CLIP, handle_3dstate_viewport_state_pointers_sf_clip },
> + { _3DSTATE_BLEND_STATE_POINTERS, handle_3dstate_blend_state_pointers },
> + { _3DSTATE_CC_STATE_POINTERS, handle_3dstate_cc_state_pointers },
> + { _3DSTATE_SCISSOR_STATE_POINTERS, handle_3dstate_scissor_state_pointers }
> +};
> +
> +static void
> +parse_commands(struct gen_spec *spec, uint32_t *cmds, int size, int engine)
> +{
> + uint32_t *p, *end = cmds + size / 4;
> + unsigned int length, i;
> + struct gen_group *inst;
> +
> + for (p = cmds; p < end; p += length) {
> + inst = gen_spec_find_instruction(spec, p);
> + if (inst == NULL) {
> + printf("unknown instruction %08x\n", p[0]);
> + length = (p[0] & 0xff) + 2;
> + continue;
> + }
> + length = gen_group_get_length(inst, p);
> +
> + const char *color, *reset_color = CLEAR_TO_EOL NORMAL;
> + uint64_t offset;
> +
> + if (option_full_decode)
> + color = HEADER;
> + else
> + color = NORMAL;
> +
> + if (option_color == COLOR_NEVER) {
> + color = "";
> + reset_color = "";
> + }
> +
> + if (option_print_offsets)
> + offset = (void *) p - gtt;
> + else
> + offset = 0;
> +
> + printf("%s0x%08lx: 0x%08x: %s%s\n",
> + color, offset, p[0],
> + gen_group_get_name(inst), reset_color);
> +
> + if (option_full_decode) {
> + struct gen_field_iterator iter;
> + gen_field_iterator_init(&iter, inst, p);
> + while (gen_field_iterator_next(&iter)) {
> + printf(" %s: %s\n", iter.name, iter.value);
> + }
> +
> + for (i = 0; i < ARRAY_LENGTH(custom_handlers); i++) {
> + if (gen_group_get_opcode(inst) ==
> + custom_handlers[i].opcode)
> + custom_handlers[i].handle(spec, p);
> + }
> + }
> +
> + if ((p[0] & 0xffff0000) == AUB_MI_BATCH_BUFFER_START) {
> + uint64_t start;
> + if (gen_spec_get_gen(spec) >= gen_make_gen(8,0))
> + start = get_qword(&p[1]);
> + else
> + start = p[1];
> +
> + parse_commands(spec, gtt + start, 1 << 20, engine);
> + } else if ((p[0] & 0xffff0000) == AUB_MI_BATCH_BUFFER_END) {
> + break;
> + }
> + }
> +}
> +
> +#define GEN_ENGINE_RENDER 1
> +#define GEN_ENGINE_BLITTER 2
> +
> +static void
> +handle_trace_block(struct gen_spec *spec, uint32_t *p)
> +{
> + int operation = p[1] & AUB_TRACE_OPERATION_MASK;
> + int type = p[1] & AUB_TRACE_TYPE_MASK;
> + int address_space = p[1] & AUB_TRACE_ADDRESS_SPACE_MASK;
> + uint64_t offset = p[3];
> + uint32_t size = p[4];
> + int header_length = p[0] & 0xffff;
> + uint32_t *data = p + header_length + 2;
> + int engine = GEN_ENGINE_RENDER;
> +
> + if (gen_spec_get_gen(spec) >= gen_make_gen(8,0))
> + offset += (uint64_t) p[5] << 32;
> +
> + switch (operation) {
> + case AUB_TRACE_OP_DATA_WRITE:
> + if (address_space != AUB_TRACE_MEMTYPE_GTT)
> + break;
> + if (gtt_size < offset + size)
> + error(EXIT_FAILURE, errno, "overflow gtt space");
> + memcpy((char *) gtt + offset, data, size);
> + if (gtt_end < offset + size)
> + gtt_end = offset + size;
> + break;
> + case AUB_TRACE_OP_COMMAND_WRITE:
> + switch (type) {
> + case AUB_TRACE_TYPE_RING_PRB0:
> + engine = GEN_ENGINE_RENDER;
> + break;
> + case AUB_TRACE_TYPE_RING_PRB2:
> + engine = GEN_ENGINE_BLITTER;
> + break;
> + default:
> + printf("command write to unknown ring %d\n", type);
> + break;
> + }
> +
> + parse_commands(spec, data, size, engine);
> + gtt_end = 0;
> + break;
> + }
> +}
> +
> +struct aub_file {
> + char *filename;
> + int fd;
> + struct stat sb;
> + uint32_t *map, *end, *cursor;
> +};
> +
> +static struct aub_file *
> +aub_file_open(const char *filename)
> +{
> + struct aub_file *file;
> +
> + file = malloc(sizeof *file);
> + file->filename = strdup(filename);
> + file->fd = open(file->filename, O_RDONLY);
> + if (file->fd == -1)
> + error(EXIT_FAILURE, errno, "open %s failed", file->filename);
> +
> + if (fstat(file->fd, &file->sb) == -1)
> + error(EXIT_FAILURE, errno, "stat failed");
> +
> + file->map = mmap(NULL, file->sb.st_size,
> + PROT_READ, MAP_SHARED, file->fd, 0);
> + if (file->map == MAP_FAILED)
> + error(EXIT_FAILURE, errno, "mmap failed");
> +
> + file->cursor = file->map;
> + file->end = file->map + file->sb.st_size / 4;
> +
> + /* mmap a terabyte for our gtt space. */
> + gtt_size = 1ul << 40;
> + gtt = mmap(NULL, gtt_size, PROT_READ | PROT_WRITE,
> + MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
> + if (gtt == MAP_FAILED)
> + error(EXIT_FAILURE, errno, "failed to alloc gtt space");
> +
> + return file;
> +}
> +
> +#define TYPE(dw) (((dw) >> 29) & 7)
> +#define OPCODE(dw) (((dw) >> 23) & 0x3f)
> +#define SUBOPCODE(dw) (((dw) >> 16) & 0x7f)
> +
> +#define MAKE_HEADER(type, opcode, subopcode) \
> + (((type) << 29) | ((opcode) << 23) | ((subopcode) << 16))
> +
> +#define TYPE_AUB 0x7
> +
> +/* Classic AUB opcodes */
> +#define OPCODE_AUB 0x01
> +#define SUBOPCODE_HEADER 0x05
> +#define SUBOPCODE_BLOCK 0x41
> +#define SUBOPCODE_BMP 0x1e
> +
> +/* Newer version AUB opcode*/
> +#define OPCODE_NEW_AUB 0x2e
> +#define SUBOPCODE_VERSION 0x00
> +#define SUBOPCODE_REG_WRITE 0x03
> +#define SUBOPCODE_MEM_POLL 0x05
> +#define SUBOPCODE_MEM_WRITE 0x06
> +
> +#define MAKE_GEN(major, minor) ( ((major) << 8) | (minor) )
> +
> +struct { const char *name; uint32_t gen; } device_map[] = {
> + { "bwr", MAKE_GEN(4, 0) },
> + { "cln", MAKE_GEN(4, 0) },
> + { "blc", MAKE_GEN(4, 0) },
> + { "ctg", MAKE_GEN(4, 0) },
> + { "el", MAKE_GEN(4, 0) },
> + { "il", MAKE_GEN(4, 0) },
> + { "sbr", MAKE_GEN(6, 0) },
> + { "ivb", MAKE_GEN(7, 0) },
> + { "lrb2", MAKE_GEN(0, 0) },
I wonder what the heck lrb2 is. By the "sbr" name I assume these names
were chosen to match the simulator.
> + { "hsw", MAKE_GEN(7, 5) },
> + { "vlv", MAKE_GEN(7, 0) },
> + { "bdw", MAKE_GEN(8, 0) },
> + { "skl", MAKE_GEN(9, 0) },
> + { "chv", MAKE_GEN(8, 0) },
> + { "bxt", MAKE_GEN(9, 0) }
> +};
> +
> +static void
> +aub_file_decode_batch(struct aub_file *file, struct gen_spec *spec)
> +{
> + uint32_t *p, h, device, data_type;
> + int header_length, payload_size, bias;
> +
> + p = file->cursor;
> + h = *p;
> + header_length = h & 0xffff;
> +
> + switch (OPCODE(h)) {
> + case OPCODE_AUB:
> + bias = 2;
> + break;
> + case OPCODE_NEW_AUB:
> + bias = 1;
> + break;
> + default:
> + printf("unknown opcode %d at %ld/%ld\n",
> + OPCODE(h), file->cursor - file->map,
> + file->end - file->map);
> + file->cursor = file->end;
> + return;
> + }
> +
> + payload_size = 0;
> + switch (h & 0xffff0000) {
> + case MAKE_HEADER(TYPE_AUB, OPCODE_AUB, SUBOPCODE_HEADER):
> + payload_size = p[12];
> + break;
> + case MAKE_HEADER(TYPE_AUB, OPCODE_AUB, SUBOPCODE_BLOCK):
> + payload_size = p[4];
> + handle_trace_block(spec, p);
> + break;
> + case MAKE_HEADER(TYPE_AUB, OPCODE_AUB, SUBOPCODE_BMP):
> + break;
> +
> + case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_VERSION):
> + printf("version block: dw1 %08x\n", p[1]);
> + device = (p[1] >> 8) & 0xff;
> + printf(" device %s\n", device_map[device].name);
> + break;
> + case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_REG_WRITE):
> + printf("register write block: (dwords %d)\n", h & 0xffff);
> + printf(" reg 0x%x, data 0x%x\n", p[1], p[5]);
> + break;
> + case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_MEM_WRITE):
> + printf("memory write block (dwords %d):\n", h & 0xffff);
> + printf(" address 0x%lx\n", *(uint64_t *) &p[1]);
> + data_type = (p[3] >> 20) & 0xff;
> + if (data_type != 0)
> + printf(" data type 0x%x\n", data_type);
> + printf(" address space 0x%x\n", (p[3] >> 28) & 0xf);
> + break;
> + case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_MEM_POLL):
> + printf("memory poll block (dwords %d):\n", h & 0xffff);
> + break;
> + default:
> + printf("unknown block type=0x%x, opcode=0x%x, "
> + "subopcode=0x%x (%08x)\n", TYPE(h), OPCODE(h), SUBOPCODE(h), h);
> + break;
> + }
> + file->cursor = p + header_length + bias + payload_size / 4;
> +}
> +
> +static int
> +aub_file_more_stuff(struct aub_file *file)
> +{
> + return file->cursor < file->end;
> +}
> +
> +static void
> +setup_pager(void)
> +{
> + int fds[2];
> + pid_t pid;
> +
> + if (!isatty(1))
> + return;
> +
> + if (pipe(fds) == -1)
> + return;
> +
> + pid = fork();
> + if (pid == -1)
> + return;
> +
> + if (pid == 0) {
> + close(fds[1]);
> + dup2(fds[0], 0);
> + execlp("less", "less", "-rFi", NULL);
> + }
> +
> + close(fds[0]);
> + dup2(fds[1], 1);
> + close(fds[1]);
> +}
> +
> +static void
> +print_help(FILE *file)
> +{
> + fprintf(file,
> + "Usage: %s [OPTION]... FILE\n"
> + "Decode aub file contents.\n\n"
> + "A valid --gen option must be provided.\n\n"
> + " --help display this help and exit\n"
> + " --gen=GEN decode for given gen (7, 7.5, 8 or 9)\n"
> + " --headers decode only command headers\n"
> + " --color[=WHEN] colorize the output; WHEN can be 'auto' (default\n"
> + " if omitted), 'always', or 'never'\n"
> + " --no-pager don't launch pager\n"
> + " --no-offsets don't print instruction offsets\n",
> + basename(program_invocation_name));
> +}
> +
> +static bool
> +is_prefix(const char *arg, const char *prefix, const char **value)
> +{
> + int l = strlen(prefix);
> +
> + if (strncmp(arg, prefix, l) == 0 && (arg[l] == '\0' || arg[l] == '=')) {
> + if (arg[l] == '=')
> + *value = arg + l + 1;
> + else
> + *value = NULL;
> +
> + return true;
> + }
> +
> + return false;
> +}
> +
> +int main(int argc, char *argv[])
> +{
> + struct gen_spec *spec;
> + struct aub_file *file;
> + int i, pci_id = 0;
> + bool found_arg_gen = false, pager = true;
> + int gen_major, gen_minor;
> + const char *value;
> + char gen_file[256];
> +
> + for (i = 1; i < argc; ++i) {
> + if (strcmp(argv[i], "--no-pager") == 0) {
> + pager = false;
> + } else if (strcmp(argv[i], "--no-offsets") == 0) {
> + option_print_offsets = false;
> + } else if (is_prefix(argv[i], "--gen", &value)) {
> + if (value == NULL)
> + error(EXIT_FAILURE, 0, "option '--gen' requires an argument\n");
> +
> + found_arg_gen = true;
> + gen_major = 0;
> + gen_minor = 0;
> +
> + if (sscanf(value, "%d.%d", &gen_major, &gen_minor) == 2) {
> + continue;
> + } else if (sscanf(value, "%d", &gen_major) == 1) {
> + continue;
> + } else {
> + error(EXIT_FAILURE, 0, "can't parse gen: %s, expected 7, 7.5, 8 or 9\n", value);
> + }
> + } else if (strcmp(argv[i], "--headers") == 0) {
> + option_full_decode = false;
> + } else if (is_prefix(argv[i], "--color", &value)) {
> + if (value == NULL || strcmp(value, "always") == 0)
> + option_color = COLOR_ALWAYS;
> + else if (strcmp(value, "never") == 0)
> + option_color = COLOR_NEVER;
> + else if (strcmp(value, "auto") == 0)
> + option_color = COLOR_AUTO;
> + else
> + error(EXIT_FAILURE, 0, "invalid value for --color: %s", value);
> + } else if (strcmp(argv[i], "--help") == 0) {
> + print_help(stdout);
> + exit(EXIT_SUCCESS);
> + } else {
> + break;
> + }
> + }
> +
> + if (argv[i] == NULL) {
> + print_help(stderr);
> + exit(EXIT_FAILURE);
> + }
> +
> + if (argv[i][0] == '-') {
> + fprintf(stderr, "unknown option %s\n", argv[i]);
> + exit(EXIT_FAILURE);
> + }
> +
> + if (!found_arg_gen) {
> + fprintf(stderr, "argument --gen is required\n");
> + exit(EXIT_FAILURE);
> + }
> +
> + switch (MAKE_GEN(gen_major, gen_minor)) {
> + case MAKE_GEN(7, 0):
> + /* Intel(R) Ivybridge Mobile GT2 */
> + pci_id = 0x0166;
> + break;
> + case MAKE_GEN(7, 5):
> + /* Intel(R) Haswell Mobile GT2 */
> + pci_id = 0x0416;
> + break;
> + case MAKE_GEN(8, 0):
> + /* Intel(R) HD Graphics 5500 (Broadwell GT2) */
> + pci_id = 0x1616;
> + break;
> + case MAKE_GEN(9, 0):
> + /* PCI_CHIP_SKYLAKE_DT_GT2 */
> + pci_id = 0x1912;
> + break;
> + default:
> + fprintf(stderr, "gen %d.%d is unknown\n", gen_major, gen_minor);
> + exit(EXIT_FAILURE);
> + }
> +
> + /* Do this before we redirect stdout to pager. */
> + if (option_color == COLOR_AUTO)
> + option_color = isatty(1) ? COLOR_ALWAYS : COLOR_NEVER;
> +
> + if (isatty(1) && pager)
> + setup_pager();
> +
> + if (gen_minor > 0)
> + snprintf(gen_file, sizeof(gen_file), "../genxml/gen%d%d.xml", gen_major, gen_minor);
> + else
> + snprintf(gen_file, sizeof(gen_file), "../genxml/gen%d.xml", gen_major);
> +
> + spec = gen_spec_load(gen_file);
> +
> + disasm = gen_disasm_create(gen_major);
> +
> + file = aub_file_open(argv[i]);
> +
> + while (aub_file_more_stuff(file))
> + aub_file_decode_batch(file, spec);
> +
> + fflush(stdout);
> + close(1);
> +
> + wait(NULL);
> +
> + return EXIT_SUCCESS;
> +}
> diff --git a/src/intel/tools/decoder.c b/src/intel/tools/decoder.c
> new file mode 100644
> index 0000000..7ab3696
> --- /dev/null
> +++ b/src/intel/tools/decoder.c
> @@ -0,0 +1,520 @@
> +/*
> + * Copyright © 2016 Intel Corporation
> + *
> + * 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.
> + */
> +
> +#define _DEFAULT_SOURCE /* for strdup() */
> +
> +#include <stdio.h>
> +#include <stdbool.h>
> +#include <stdint.h>
> +#include <stdarg.h>
> +#include <string.h>
> +#include <expat.h>
> +
> +#include <util/macros.h>
> +
> +#include "decoder.h"
> +
> +#define XML_BUFFER_SIZE 4096
> +
> +#define MAKE_GEN(major, minor) ( ((major) << 8) | (minor) )
> +
> +struct gen_spec {
> + uint32_t gen;
> +
> + int ncommands;
> + struct gen_group *commands[256];
> + int nstructs;
> + struct gen_group *structs[256];
> + int nregisters;
> + struct gen_group *registers[256];
> +};
> +
> +struct gen_group {
> + char *name;
> + int nfields;
> + struct gen_field **fields;
> +
> + uint32_t opcode_mask;
> + uint32_t opcode;
> +};
> +
> +struct gen_type {
> + enum {
> + GEN_TYPE_UNKNOWN,
> + GEN_TYPE_INT,
> + GEN_TYPE_UINT,
> + GEN_TYPE_BOOL,
> + GEN_TYPE_FLOAT,
> + GEN_TYPE_ADDRESS,
> + GEN_TYPE_OFFSET,
> + GEN_TYPE_STRUCT,
> + GEN_TYPE_UFIXED,
> + GEN_TYPE_SFIXED,
> + GEN_TYPE_MBO
> + } kind;
> +
> + /* Struct definition for GEN_TYPE_STRUCT*/
Space before */
> + struct gen_group *gen_struct;
> +
> + /* Integer and fractional sizes for GEN_TYPE_UFIXED and GEN_TYPE_SFIXED */
> + int i, f;
> +};
> +
> +struct gen_field {
> + char *name;
> + int start, end;
> + struct gen_type type;
> + bool has_default;
> + uint32_t default_value;
> +};
> +
> +struct location {
> + const char *filename;
> + int line_number;
> +};
> +
> +struct parser_context {
> + XML_Parser parser;
> + int foo;
> + struct location loc;
> + const char *platform;
> +
> + struct gen_group *group;
> +
> + int nfields;
> + struct gen_field *fields[128];
> +
> + struct gen_spec *spec;
> +};
> +
> +const char *
> +gen_group_get_name(struct gen_group *group)
> +{
> + return group->name;
> +}
> +
> +uint32_t
> +gen_group_get_opcode(struct gen_group *group)
> +{
> + return group->opcode;
> +}
> +
> +struct gen_group *
> +gen_spec_find_struct(struct gen_spec *spec, const char *name)
> +{
> + for (int i = 0; i < spec->nstructs; i++)
> + if (strcmp(spec->structs[i]->name, name) == 0)
> + return spec->structs[i];
> +
> + return NULL;
> +}
> +
> +uint32_t
> +gen_spec_get_gen(struct gen_spec *spec)
> +{
> + return spec->gen;
> +}
> +
> +static void __attribute__((noreturn))
> +fail(struct location *loc, const char *msg, ...)
> +{
> + va_list ap;
> +
> + va_start(ap, msg);
> + fprintf(stderr, "%s:%d: error: ",
> + loc->filename, loc->line_number);
> + vfprintf(stderr, msg, ap);
> + fprintf(stderr, "\n");
> + va_end(ap);
> + exit(EXIT_FAILURE);
> +}
> +
> +static void *
> +fail_on_null(void *p)
> +{
> + if (p == NULL) {
> + fprintf(stderr, "wayland-scanner: out of memory\n");
wayland-scanner? Copy and paste left over I think.
> + exit(EXIT_FAILURE);
> + }
> +
> + return p;
> +}
> +
> +static char *
> +xstrdup(const char *s)
> +{
> + return fail_on_null(strdup(s));
> +}
> +
> +static void *
> +zalloc(size_t s)
> +{
> + return calloc(s, 1);
> +}
> +
> +static void *
> +xzalloc(size_t s)
> +{
> + return fail_on_null(zalloc(s));
> +}
> +
> +static struct gen_group *
> +create_group(struct parser_context *ctx, const char *name, const char **atts)
> +{
> + struct gen_group *group;
> +
> + group = xzalloc(sizeof(*group));
> + if (name)
> + group->name = xstrdup(name);
> +
> + return group;
> +}
> +
> +static inline uint64_t
> +mask(int start, int end)
> +{
> + uint64_t v;
> +
> + v = ~0ULL >> (63 - end + start);
> +
> + return v << start;
> +}
> +
> +static inline uint64_t
> +field(uint64_t value, int start, int end)
> +{
> + return (value & mask(start, end)) >> start;
> +}
> +
> +static struct gen_type
> +string_to_type(struct parser_context *ctx, const char *s)
> +{
> + int i, f;
> + struct gen_group *g;
> +
> + if (strcmp(s, "int") == 0)
> + return (struct gen_type) { .kind = GEN_TYPE_INT };
> + else if (strcmp(s, "uint") == 0)
> + return (struct gen_type) { .kind = GEN_TYPE_UINT };
> + else if (strcmp(s, "bool") == 0)
> + return (struct gen_type) { .kind = GEN_TYPE_BOOL };
> + else if (strcmp(s, "float") == 0)
> + return (struct gen_type) { .kind = GEN_TYPE_FLOAT };
> + else if (strcmp(s, "address") == 0)
> + return (struct gen_type) { .kind = GEN_TYPE_ADDRESS };
> + else if (strcmp(s, "offset") == 0)
> + return (struct gen_type) { .kind = GEN_TYPE_OFFSET };
> + else if (sscanf(s, "u%d.%d", &i, &f) == 2)
> + return (struct gen_type) { .kind = GEN_TYPE_UFIXED, .i = i, .f = f };
> + else if (sscanf(s, "s%d.%d", &i, &f) == 2)
> + return (struct gen_type) { .kind = GEN_TYPE_SFIXED, .i = i, .f = f };
> + else if (g = gen_spec_find_struct(ctx->spec, s), g != NULL)
> + return (struct gen_type) { .kind = GEN_TYPE_STRUCT, .gen_struct = g };
> + else if (strcmp(s, "mbo") == 0)
> + return (struct gen_type) { .kind = GEN_TYPE_MBO };
> + else
> + fail(&ctx->loc, "invalid type: %s", s);
> +}
> +
> +static struct gen_field *
> +create_field(struct parser_context *ctx, const char **atts)
> +{
> + struct gen_field *field;
> + char *p;
> + int i;
> +
> + field = xzalloc(sizeof(*field));
> +
> + for (i = 0; atts[i]; i += 2) {
> + if (strcmp(atts[i], "name") == 0)
> + field->name = xstrdup(atts[i + 1]);
> + else if (strcmp(atts[i], "start") == 0)
> + field->start = strtoul(atts[i + 1], &p, 0);
> + else if (strcmp(atts[i], "end") == 0)
> + field->end = strtoul(atts[i + 1], &p, 0);
> + else if (strcmp(atts[i], "type") == 0)
> + field->type = string_to_type(ctx, atts[i + 1]);
> + else if (strcmp(atts[i], "default") == 0 &&
> + field->start >= 16 && field->end <= 31) {
> + field->has_default = true;
> + field->default_value = strtoul(atts[i + 1], &p, 0);
> + }
> + }
> +
> + return field;
> +}
> +
> +static void
> +start_element(void *data, const char *element_name, const char **atts)
> +{
> + struct parser_context *ctx = data;
> + int i;
> + const char *name = NULL;
> + const char *gen = NULL;
> +
> + ctx->loc.line_number = XML_GetCurrentLineNumber(ctx->parser);
> +
> + for (i = 0; atts[i]; i += 2) {
> + if (strcmp(atts[i], "name") == 0)
> + name = atts[i + 1];
> + else if (strcmp(atts[i], "gen") == 0)
> + gen = atts[i + 1];
> + }
> +
> + if (strcmp(element_name, "genxml") == 0) {
> + if (name == NULL)
> + fail(&ctx->loc, "no platform name given");
> + if (gen == NULL)
> + fail(&ctx->loc, "no gen given");
> +
> + ctx->platform = xstrdup(name);
> + int major, minor;
> + int n = sscanf(gen, "%d.%d", &major, &minor);
> + if (n == 0)
> + fail(&ctx->loc, "invalid gen given: %s", gen);
> + if (n == 1)
> + minor = 0;
> +
> + ctx->spec->gen = MAKE_GEN(major, minor);
> + } else if (strcmp(element_name, "instruction") == 0 ||
> + strcmp(element_name, "struct") == 0 ||
> + strcmp(element_name, "register") == 0) {
> + ctx->group = create_group(ctx, name, atts);
> + } else if (strcmp(element_name, "group") == 0) {
Really nothing to do here...
> + } else if (strcmp(element_name, "field") == 0) {
> + ctx->fields[ctx->nfields++] = create_field(ctx, atts);
> + } else if (strcmp(element_name, "enum") == 0) {
here...
> + } else if (strcmp(element_name, "value") == 0) {
or here...?
> + }
> +}
> +
> +static void
> +end_element(void *data, const char *name)
> +{
> + struct parser_context *ctx = data;
> +
> + if (strcmp(name, "instruction") == 0 ||
> + strcmp(name, "struct") == 0 ||
> + strcmp(name, "register") == 0) {
> + size_t size = ctx->nfields * sizeof(ctx->fields[0]);
> + struct gen_group *group = ctx->group;
> +
> + group->fields = xzalloc(size);
> + group->nfields = ctx->nfields;
> + memcpy(group->fields, ctx->fields, size);
> + ctx->nfields = 0;
> + ctx->group = NULL;
> +
> + for (int i = 0; i < group->nfields; i++) {
> + if (group->fields[i]->start >= 16 &&
> + group->fields[i]->end <= 31 &&
> + group->fields[i]->has_default) {
> + group->opcode_mask |=
> + mask(group->fields[i]->start, group->fields[i]->end);
> + group->opcode |=
> + group->fields[i]->default_value << group->fields[i]->start;
> + }
> + }
> +
> + struct gen_spec *spec = ctx->spec;
> + if (strcmp(name, "instruction") == 0)
> + spec->commands[spec->ncommands++] = group;
> + else if (strcmp(name, "struct") == 0)
> + spec->structs[spec->nstructs++] = group;
> + else if (strcmp(name, "register") == 0)
> + spec->registers[spec->nregisters++] = group;
> + }
> +}
> +
> +static void
> +character_data(void *data, const XML_Char *s, int len)
> +{
> +}
> +
> +struct gen_spec *
> +gen_spec_load(const char *filename)
> +{
> + struct parser_context ctx;
> + void *buf;
> + int len;
> + FILE *input;
> +
> + input = fopen(filename, "r");
> + printf("xml filename = %s\n", filename);
> + if (input == NULL) {
> + fprintf(stderr, "failed to open xml description\n");
> + exit(EXIT_FAILURE);
> + }
> +
> + memset(&ctx, 0, sizeof ctx);
> + ctx.parser = XML_ParserCreate(NULL);
> + XML_SetUserData(ctx.parser, &ctx);
> + if (ctx.parser == NULL) {
> + fprintf(stderr, "failed to create parser\n");
> + fclose(input);
> + return NULL;
> + }
> +
> + XML_SetElementHandler(ctx.parser, start_element, end_element);
> + XML_SetCharacterDataHandler(ctx.parser, character_data);
> + ctx.loc.filename = filename;
> +
> + ctx.spec = xzalloc(sizeof(*ctx.spec));
> +
> + do {
> + buf = XML_GetBuffer(ctx.parser, XML_BUFFER_SIZE);
> + len = fread(buf, 1, XML_BUFFER_SIZE, input);
> + if (len < 0) {
> + fprintf(stderr, "fread: %m\n");
> + fclose(input);
> + return NULL;
> + }
> + if (XML_ParseBuffer(ctx.parser, len, len == 0) == 0) {
> + fprintf(stderr,
> + "Error parsing XML at line %ld col %ld: %s\n",
> + XML_GetCurrentLineNumber(ctx.parser),
> + XML_GetCurrentColumnNumber(ctx.parser),
> + XML_ErrorString(XML_GetErrorCode(ctx.parser)));
> + fclose(input);
> + return NULL;
> + }
> + } while (len > 0);
> +
> + XML_ParserFree(ctx.parser);
> + fclose(input);
> +
> + return ctx.spec;
> +}
> +
> +struct gen_group *
> +gen_spec_find_instruction(struct gen_spec *spec, const uint32_t *p)
> +{
> + /* FIX ME: Make sure the opcodes put out are correct */
FIXME comments are harder to find if there's a space in the middle. :)
> + for (int i = 0; i < spec->ncommands; i++) {
> + uint32_t opcode = *p & spec->commands[i]->opcode_mask;
> + if (opcode == spec->commands[i]->opcode)
> + return spec->commands[i];
> + }
> +
> + return NULL;
> +}
> +
> +int
> +gen_group_get_length(struct gen_group *group, const uint32_t *p)
> +{
> + uint32_t h = p[0];
> + uint32_t type = field(h, 29, 31);
> +
> + switch (type) {
> + case 0: /* MI */ {
> + uint32_t opcode = field(h, 23, 28);
> + if (opcode < 16)
> + return 1;
> + else
> + return field(h, 0, 7) + 2;
> + break;
> + }
> +
> + case 3: /* Render */ {
> + uint32_t subtype = field(h, 27, 28);
> + switch (subtype) {
> + case 0:
> + return field(h, 0, 7) + 2;
> + case 1:
> + return 1;
> + case 2:
> + return 2;
> + case 3:
> + return field(h, 0, 7) + 2;
> + }
> + }
> + }
> +
> + unreachable("bad opcode");
> +}
> +
> +void
> +gen_field_iterator_init(struct gen_field_iterator *iter,
> + struct gen_group *group, const uint32_t *p)
> +{
> + iter->group = group;
> + iter->p = p;
> + iter->i = 0;
> +}
> +
> +bool
> +gen_field_iterator_next(struct gen_field_iterator *iter)
> +{
> + struct gen_field *f;
> + union {
> + uint32_t dw;
> + float f;
> + } v;
> +
> + if (iter->i == iter->group->nfields)
> + return false;
> +
> + f = iter->group->fields[iter->i++];
> + iter->name = f->name;
> + v.dw = iter->p[f->start / 32];
> + switch (f->type.kind) {
> + case GEN_TYPE_UNKNOWN:
> + case GEN_TYPE_INT:
> + snprintf(iter->value, sizeof(iter->value),
> + "%ld", field(v.dw, f->start, f->end));
> + break;
> + case GEN_TYPE_UINT:
> + snprintf(iter->value, sizeof(iter->value),
> + "%lu", field(v.dw, f->start, f->end));
> + break;
> + case GEN_TYPE_BOOL:
> + snprintf(iter->value, sizeof(iter->value),
> + "%s", field(v.dw, f->start, f->end) ? "true" : "false");
> + break;
> + case GEN_TYPE_FLOAT:
> + snprintf(iter->value, sizeof(iter->value), "%f", v.f);
> + break;
> + case GEN_TYPE_ADDRESS:
> + case GEN_TYPE_OFFSET:
> + snprintf(iter->value, sizeof(iter->value),
> + "0x%08lx", field(v.dw, f->start, f->end));
> + break;
> + case GEN_TYPE_STRUCT:
> + /* FIXME: Make iterator decode the struct recursively */
> + snprintf(iter->value, sizeof(iter->value),
> + "<struct %s>", f->type.gen_struct->name);
> + break;
> + case GEN_TYPE_UFIXED:
> + snprintf(iter->value, sizeof(iter->value),
> + "%f", (float) field(v.dw, f->start, f->end) / (1 << f->type.f));
> + break;
> + case GEN_TYPE_SFIXED:
> + /* FIXME: Sign extend extracted field. */
> + snprintf(iter->value, sizeof(iter->value), "%s", "foo");
> + break;
> + case GEN_TYPE_MBO:
> + break;
> + }
> +
> + return true;
> +}
> diff --git a/src/intel/tools/decoder.h b/src/intel/tools/decoder.h
> new file mode 100644
> index 0000000..af9e075
> --- /dev/null
> +++ b/src/intel/tools/decoder.h
> @@ -0,0 +1,57 @@
> +/*
> + * Copyright © 2016 Intel Corporation
> + *
> + * 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.
> + */
> +
> +#pragma once
> +
> +#include <stdint.h>
> +#include <stdbool.h>
> +
> +struct gen_spec;
> +struct gen_group;
> +struct gen_field;
> +
> +static inline uint32_t gen_make_gen(uint32_t major, uint32_t minor)
> +{
> + return (major << 8) | minor;
> +}
> +
> +struct gen_group *gen_spec_find_struct(struct gen_spec *spec, const char *name);
> +struct gen_spec *gen_spec_load(const char *filename);
> +uint32_t gen_spec_get_gen(struct gen_spec *spec);
> +struct gen_group *gen_spec_find_instruction(struct gen_spec *spec, const uint32_t *p);
> +int gen_group_get_length(struct gen_group *group, const uint32_t *p);
> +const char *gen_group_get_name(struct gen_group *group);
> +uint32_t gen_group_get_opcode(struct gen_group *group);
> +
> +struct gen_field_iterator {
> + struct gen_group *group;
> + const char *name;
> + char value[128];
> + uint32_t *p;
> + int i;
> +};
> +
> +void gen_field_iterator_init(struct gen_field_iterator *iter,
> + struct gen_group *group, const uint32_t *p);
> +
> +bool gen_field_iterator_next(struct gen_field_iterator *iter);
> diff --git a/src/intel/tools/disasm.c b/src/intel/tools/disasm.c
> new file mode 100644
> index 0000000..6f28a87
> --- /dev/null
> +++ b/src/intel/tools/disasm.c
> @@ -0,0 +1,109 @@
> +/*
> + * Copyright © 2014 Intel Corporation
> + *
> + * 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 "brw_context.h"
> +#include "brw_inst.h"
> +#include "brw_eu.h"
> +
> +#include "gen_disasm.h"
> +
> +uint64_t INTEL_DEBUG;
> +
> +struct gen_disasm {
> + struct brw_device_info devinfo;
> +};
> +
> +void
> +gen_disasm_disassemble(struct gen_disasm *disasm,
> + void *assembly, int start, int end, FILE *out)
> +{
> + struct brw_device_info *devinfo = &disasm->devinfo;
> + bool dump_hex = false;
> +
> + for (int offset = start; offset < end;) {
> + brw_inst *insn = assembly + offset;
> + brw_inst uncompacted;
> + bool compacted = brw_inst_cmpt_control(devinfo, insn);
> + if (0)
> + fprintf(out, "0x%08x: ", offset);
> +
> + if (compacted) {
> + brw_compact_inst *compacted = (void *)insn;
> + if (dump_hex) {
> + fprintf(out, "0x%08x 0x%08x ",
> + ((uint32_t *)insn)[1],
> + ((uint32_t *)insn)[0]);
> + }
> +
> + brw_uncompact_instruction(devinfo, &uncompacted, compacted);
> + insn = &uncompacted;
> + offset += 8;
> + } else {
> + if (dump_hex) {
> + fprintf(out, "0x%08x 0x%08x 0x%08x 0x%08x ",
> + ((uint32_t *)insn)[3],
> + ((uint32_t *)insn)[2],
> + ((uint32_t *)insn)[1],
> + ((uint32_t *)insn)[0]);
> + }
> + offset += 16;
> + }
> +
> + brw_disassemble_inst(out, devinfo, insn, compacted);
> +
> + /* Simplistic, but efficient way to terminate disasm */
> + if (brw_inst_opcode(devinfo, insn) == BRW_OPCODE_SEND ||
> + brw_inst_opcode(devinfo, insn) == BRW_OPCODE_SENDC)
> + if (brw_inst_eot(devinfo, insn))
> + break;
> + if (brw_inst_opcode(devinfo, insn) == 0)
> + break;
> +
> + }
> +}
> +
> +struct gen_disasm *
> +gen_disasm_create(int gen)
> +{
> + struct gen_disasm *gd;
> +
> + gd = malloc(sizeof *gd);
> + if (gd == NULL)
> + return NULL;
> +
> + gd->devinfo.gen = gen;
> + gd->devinfo.is_cherryview = 0;
> + gd->devinfo.is_g4x = 0;
> +
> + brw_init_compaction_tables(&gd->devinfo);
This isn't going to work, obviously for g4x and cherryview. There are
differences in the compaction code. I suppose we need to provide this
information to gen_disasm_create.
More information about the mesa-dev
mailing list