On Tue, Aug 9, 2016 at 4:52 PM, Sirisha Gandikota <sirisha.gandik...@intel.com> wrote: > From: Kristian Høgsberg Kristensen <k...@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.lesp...@intel.com> > and Kristian Høgsberg Kristensen <k...@bitplanet.net>. > > Signed-off-by: Sirisha Gandikota <sirisha.gandik...@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. _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev