1b8e80941Smrg/*
2b8e80941Smrg * Copyright © 2016 Intel Corporation
3b8e80941Smrg *
4b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5b8e80941Smrg * copy of this software and associated documentation files (the "Software"),
6b8e80941Smrg * to deal in the Software without restriction, including without limitation
7b8e80941Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8b8e80941Smrg * and/or sell copies of the Software, and to permit persons to whom the
9b8e80941Smrg * Software is furnished to do so, subject to the following conditions:
10b8e80941Smrg *
11b8e80941Smrg * The above copyright notice and this permission notice (including the next
12b8e80941Smrg * paragraph) shall be included in all copies or substantial portions of the
13b8e80941Smrg * Software.
14b8e80941Smrg *
15b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16b8e80941Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17b8e80941Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18b8e80941Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19b8e80941Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20b8e80941Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21b8e80941Smrg * IN THE SOFTWARE.
22b8e80941Smrg */
23b8e80941Smrg
24b8e80941Smrg#include <stdio.h>
25b8e80941Smrg#include <stdbool.h>
26b8e80941Smrg#include <stdint.h>
27b8e80941Smrg#include <stdarg.h>
28b8e80941Smrg#include <string.h>
29b8e80941Smrg#include <expat.h>
30b8e80941Smrg#include <inttypes.h>
31b8e80941Smrg#include <zlib.h>
32b8e80941Smrg
33b8e80941Smrg#include <util/macros.h>
34b8e80941Smrg#include <util/ralloc.h>
35b8e80941Smrg
36b8e80941Smrg#include "gen_decoder.h"
37b8e80941Smrg
38b8e80941Smrg#include "isl/isl.h"
39b8e80941Smrg#include "genxml/genX_xml.h"
40b8e80941Smrg
41b8e80941Smrg#define XML_BUFFER_SIZE 4096
42b8e80941Smrg#define MAX_VALUE_ITEMS 128
43b8e80941Smrg
44b8e80941Smrgstruct location {
45b8e80941Smrg   const char *filename;
46b8e80941Smrg   int line_number;
47b8e80941Smrg};
48b8e80941Smrg
49b8e80941Smrgstruct parser_context {
50b8e80941Smrg   XML_Parser parser;
51b8e80941Smrg   int foo;
52b8e80941Smrg   struct location loc;
53b8e80941Smrg
54b8e80941Smrg   struct gen_group *group;
55b8e80941Smrg   struct gen_enum *enoom;
56b8e80941Smrg
57b8e80941Smrg   int n_values, n_allocated_values;
58b8e80941Smrg   struct gen_value **values;
59b8e80941Smrg
60b8e80941Smrg   struct gen_field *last_field;
61b8e80941Smrg
62b8e80941Smrg   struct gen_spec *spec;
63b8e80941Smrg};
64b8e80941Smrg
65b8e80941Smrgconst char *
66b8e80941Smrggen_group_get_name(struct gen_group *group)
67b8e80941Smrg{
68b8e80941Smrg   return group->name;
69b8e80941Smrg}
70b8e80941Smrg
71b8e80941Smrguint32_t
72b8e80941Smrggen_group_get_opcode(struct gen_group *group)
73b8e80941Smrg{
74b8e80941Smrg   return group->opcode;
75b8e80941Smrg}
76b8e80941Smrg
77b8e80941Smrgstruct gen_group *
78b8e80941Smrggen_spec_find_struct(struct gen_spec *spec, const char *name)
79b8e80941Smrg{
80b8e80941Smrg   struct hash_entry *entry = _mesa_hash_table_search(spec->structs,
81b8e80941Smrg                                                      name);
82b8e80941Smrg   return entry ? entry->data : NULL;
83b8e80941Smrg}
84b8e80941Smrg
85b8e80941Smrgstruct gen_group *
86b8e80941Smrggen_spec_find_register(struct gen_spec *spec, uint32_t offset)
87b8e80941Smrg{
88b8e80941Smrg   struct hash_entry *entry =
89b8e80941Smrg      _mesa_hash_table_search(spec->registers_by_offset,
90b8e80941Smrg                              (void *) (uintptr_t) offset);
91b8e80941Smrg   return entry ? entry->data : NULL;
92b8e80941Smrg}
93b8e80941Smrg
94b8e80941Smrgstruct gen_group *
95b8e80941Smrggen_spec_find_register_by_name(struct gen_spec *spec, const char *name)
96b8e80941Smrg{
97b8e80941Smrg   struct hash_entry *entry =
98b8e80941Smrg      _mesa_hash_table_search(spec->registers_by_name, name);
99b8e80941Smrg   return entry ? entry->data : NULL;
100b8e80941Smrg}
101b8e80941Smrg
102b8e80941Smrgstruct gen_enum *
103b8e80941Smrggen_spec_find_enum(struct gen_spec *spec, const char *name)
104b8e80941Smrg{
105b8e80941Smrg   struct hash_entry *entry = _mesa_hash_table_search(spec->enums,
106b8e80941Smrg                                                      name);
107b8e80941Smrg   return entry ? entry->data : NULL;
108b8e80941Smrg}
109b8e80941Smrg
110b8e80941Smrguint32_t
111b8e80941Smrggen_spec_get_gen(struct gen_spec *spec)
112b8e80941Smrg{
113b8e80941Smrg   return spec->gen;
114b8e80941Smrg}
115b8e80941Smrg
116b8e80941Smrgstatic void __attribute__((noreturn))
117b8e80941Smrgfail(struct location *loc, const char *msg, ...)
118b8e80941Smrg{
119b8e80941Smrg   va_list ap;
120b8e80941Smrg
121b8e80941Smrg   va_start(ap, msg);
122b8e80941Smrg   fprintf(stderr, "%s:%d: error: ",
123b8e80941Smrg           loc->filename, loc->line_number);
124b8e80941Smrg   vfprintf(stderr, msg, ap);
125b8e80941Smrg   fprintf(stderr, "\n");
126b8e80941Smrg   va_end(ap);
127b8e80941Smrg   exit(EXIT_FAILURE);
128b8e80941Smrg}
129b8e80941Smrg
130b8e80941Smrgstatic void
131b8e80941Smrgget_group_offset_count(const char **atts, uint32_t *offset, uint32_t *count,
132b8e80941Smrg                       uint32_t *size, bool *variable)
133b8e80941Smrg{
134b8e80941Smrg   for (int i = 0; atts[i]; i += 2) {
135b8e80941Smrg      char *p;
136b8e80941Smrg
137b8e80941Smrg      if (strcmp(atts[i], "count") == 0) {
138b8e80941Smrg         *count = strtoul(atts[i + 1], &p, 0);
139b8e80941Smrg         if (*count == 0)
140b8e80941Smrg            *variable = true;
141b8e80941Smrg      } else if (strcmp(atts[i], "start") == 0) {
142b8e80941Smrg         *offset = strtoul(atts[i + 1], &p, 0);
143b8e80941Smrg      } else if (strcmp(atts[i], "size") == 0) {
144b8e80941Smrg         *size = strtoul(atts[i + 1], &p, 0);
145b8e80941Smrg      }
146b8e80941Smrg   }
147b8e80941Smrg   return;
148b8e80941Smrg}
149b8e80941Smrg
150b8e80941Smrgstatic struct gen_group *
151b8e80941Smrgcreate_group(struct parser_context *ctx,
152b8e80941Smrg             const char *name,
153b8e80941Smrg             const char **atts,
154b8e80941Smrg             struct gen_group *parent,
155b8e80941Smrg             bool fixed_length)
156b8e80941Smrg{
157b8e80941Smrg   struct gen_group *group;
158b8e80941Smrg
159b8e80941Smrg   group = rzalloc(ctx->spec, struct gen_group);
160b8e80941Smrg   if (name)
161b8e80941Smrg      group->name = ralloc_strdup(group, name);
162b8e80941Smrg
163b8e80941Smrg   group->spec = ctx->spec;
164b8e80941Smrg   group->variable = false;
165b8e80941Smrg   group->fixed_length = fixed_length;
166b8e80941Smrg   group->dword_length_field = NULL;
167b8e80941Smrg   group->dw_length = 0;
168b8e80941Smrg   group->engine_mask = I915_ENGINE_CLASS_TO_MASK(I915_ENGINE_CLASS_RENDER) |
169b8e80941Smrg                        I915_ENGINE_CLASS_TO_MASK(I915_ENGINE_CLASS_VIDEO) |
170b8e80941Smrg                        I915_ENGINE_CLASS_TO_MASK(I915_ENGINE_CLASS_COPY);
171b8e80941Smrg   group->bias = 1;
172b8e80941Smrg
173b8e80941Smrg   for (int i = 0; atts[i]; i += 2) {
174b8e80941Smrg      char *p;
175b8e80941Smrg      if (strcmp(atts[i], "length") == 0) {
176b8e80941Smrg         group->dw_length = strtoul(atts[i + 1], &p, 0);
177b8e80941Smrg      } else if (strcmp(atts[i], "bias") == 0) {
178b8e80941Smrg         group->bias = strtoul(atts[i + 1], &p, 0);
179b8e80941Smrg      } else if (strcmp(atts[i], "engine") == 0) {
180b8e80941Smrg         void *mem_ctx = ralloc_context(NULL);
181b8e80941Smrg         char *tmp = ralloc_strdup(mem_ctx, atts[i + 1]);
182b8e80941Smrg         char *save_ptr;
183b8e80941Smrg         char *tok = strtok_r(tmp, "|", &save_ptr);
184b8e80941Smrg
185b8e80941Smrg         group->engine_mask = 0;
186b8e80941Smrg         while (tok != NULL) {
187b8e80941Smrg            if (strcmp(tok, "render") == 0) {
188b8e80941Smrg               group->engine_mask |= I915_ENGINE_CLASS_TO_MASK(I915_ENGINE_CLASS_RENDER);
189b8e80941Smrg            } else if (strcmp(tok, "video") == 0) {
190b8e80941Smrg               group->engine_mask |= I915_ENGINE_CLASS_TO_MASK(I915_ENGINE_CLASS_VIDEO);
191b8e80941Smrg            } else if (strcmp(tok, "blitter") == 0) {
192b8e80941Smrg               group->engine_mask |= I915_ENGINE_CLASS_TO_MASK(I915_ENGINE_CLASS_COPY);
193b8e80941Smrg            } else {
194b8e80941Smrg               fprintf(stderr, "unknown engine class defined for instruction \"%s\": %s\n", name, atts[i + 1]);
195b8e80941Smrg            }
196b8e80941Smrg
197b8e80941Smrg            tok = strtok_r(NULL, "|", &save_ptr);
198b8e80941Smrg         }
199b8e80941Smrg
200b8e80941Smrg         ralloc_free(mem_ctx);
201b8e80941Smrg      }
202b8e80941Smrg   }
203b8e80941Smrg
204b8e80941Smrg   if (parent) {
205b8e80941Smrg      group->parent = parent;
206b8e80941Smrg      get_group_offset_count(atts,
207b8e80941Smrg                             &group->group_offset,
208b8e80941Smrg                             &group->group_count,
209b8e80941Smrg                             &group->group_size,
210b8e80941Smrg                             &group->variable);
211b8e80941Smrg   }
212b8e80941Smrg
213b8e80941Smrg   return group;
214b8e80941Smrg}
215b8e80941Smrg
216b8e80941Smrgstatic struct gen_enum *
217b8e80941Smrgcreate_enum(struct parser_context *ctx, const char *name, const char **atts)
218b8e80941Smrg{
219b8e80941Smrg   struct gen_enum *e;
220b8e80941Smrg
221b8e80941Smrg   e = rzalloc(ctx->spec, struct gen_enum);
222b8e80941Smrg   if (name)
223b8e80941Smrg      e->name = ralloc_strdup(e, name);
224b8e80941Smrg
225b8e80941Smrg   return e;
226b8e80941Smrg}
227b8e80941Smrg
228b8e80941Smrgstatic void
229b8e80941Smrgget_register_offset(const char **atts, uint32_t *offset)
230b8e80941Smrg{
231b8e80941Smrg   for (int i = 0; atts[i]; i += 2) {
232b8e80941Smrg      char *p;
233b8e80941Smrg
234b8e80941Smrg      if (strcmp(atts[i], "num") == 0)
235b8e80941Smrg         *offset = strtoul(atts[i + 1], &p, 0);
236b8e80941Smrg   }
237b8e80941Smrg   return;
238b8e80941Smrg}
239b8e80941Smrg
240b8e80941Smrgstatic void
241b8e80941Smrgget_start_end_pos(int *start, int *end)
242b8e80941Smrg{
243b8e80941Smrg   /* start value has to be mod with 32 as we need the relative
244b8e80941Smrg    * start position in the first DWord. For the end position, add
245b8e80941Smrg    * the length of the field to the start position to get the
246b8e80941Smrg    * relative postion in the 64 bit address.
247b8e80941Smrg    */
248b8e80941Smrg   if (*end - *start > 32) {
249b8e80941Smrg      int len = *end - *start;
250b8e80941Smrg      *start = *start % 32;
251b8e80941Smrg      *end = *start + len;
252b8e80941Smrg   } else {
253b8e80941Smrg      *start = *start % 32;
254b8e80941Smrg      *end = *end % 32;
255b8e80941Smrg   }
256b8e80941Smrg
257b8e80941Smrg   return;
258b8e80941Smrg}
259b8e80941Smrg
260b8e80941Smrgstatic inline uint64_t
261b8e80941Smrgmask(int start, int end)
262b8e80941Smrg{
263b8e80941Smrg   uint64_t v;
264b8e80941Smrg
265b8e80941Smrg   v = ~0ULL >> (63 - end + start);
266b8e80941Smrg
267b8e80941Smrg   return v << start;
268b8e80941Smrg}
269b8e80941Smrg
270b8e80941Smrgstatic inline uint64_t
271b8e80941Smrgfield_value(uint64_t value, int start, int end)
272b8e80941Smrg{
273b8e80941Smrg   get_start_end_pos(&start, &end);
274b8e80941Smrg   return (value & mask(start, end)) >> (start);
275b8e80941Smrg}
276b8e80941Smrg
277b8e80941Smrgstatic struct gen_type
278b8e80941Smrgstring_to_type(struct parser_context *ctx, const char *s)
279b8e80941Smrg{
280b8e80941Smrg   int i, f;
281b8e80941Smrg   struct gen_group *g;
282b8e80941Smrg   struct gen_enum *e;
283b8e80941Smrg
284b8e80941Smrg   if (strcmp(s, "int") == 0)
285b8e80941Smrg      return (struct gen_type) { .kind = GEN_TYPE_INT };
286b8e80941Smrg   else if (strcmp(s, "uint") == 0)
287b8e80941Smrg      return (struct gen_type) { .kind = GEN_TYPE_UINT };
288b8e80941Smrg   else if (strcmp(s, "bool") == 0)
289b8e80941Smrg      return (struct gen_type) { .kind = GEN_TYPE_BOOL };
290b8e80941Smrg   else if (strcmp(s, "float") == 0)
291b8e80941Smrg      return (struct gen_type) { .kind = GEN_TYPE_FLOAT };
292b8e80941Smrg   else if (strcmp(s, "address") == 0)
293b8e80941Smrg      return (struct gen_type) { .kind = GEN_TYPE_ADDRESS };
294b8e80941Smrg   else if (strcmp(s, "offset") == 0)
295b8e80941Smrg      return (struct gen_type) { .kind = GEN_TYPE_OFFSET };
296b8e80941Smrg   else if (sscanf(s, "u%d.%d", &i, &f) == 2)
297b8e80941Smrg      return (struct gen_type) { .kind = GEN_TYPE_UFIXED, .i = i, .f = f };
298b8e80941Smrg   else if (sscanf(s, "s%d.%d", &i, &f) == 2)
299b8e80941Smrg      return (struct gen_type) { .kind = GEN_TYPE_SFIXED, .i = i, .f = f };
300b8e80941Smrg   else if (g = gen_spec_find_struct(ctx->spec, s), g != NULL)
301b8e80941Smrg      return (struct gen_type) { .kind = GEN_TYPE_STRUCT, .gen_struct = g };
302b8e80941Smrg   else if (e = gen_spec_find_enum(ctx->spec, s), e != NULL)
303b8e80941Smrg      return (struct gen_type) { .kind = GEN_TYPE_ENUM, .gen_enum = e };
304b8e80941Smrg   else if (strcmp(s, "mbo") == 0)
305b8e80941Smrg      return (struct gen_type) { .kind = GEN_TYPE_MBO };
306b8e80941Smrg   else
307b8e80941Smrg      fail(&ctx->loc, "invalid type: %s", s);
308b8e80941Smrg}
309b8e80941Smrg
310b8e80941Smrgstatic struct gen_field *
311b8e80941Smrgcreate_field(struct parser_context *ctx, const char **atts)
312b8e80941Smrg{
313b8e80941Smrg   struct gen_field *field;
314b8e80941Smrg
315b8e80941Smrg   field = rzalloc(ctx->group, struct gen_field);
316b8e80941Smrg   field->parent = ctx->group;
317b8e80941Smrg
318b8e80941Smrg   for (int i = 0; atts[i]; i += 2) {
319b8e80941Smrg      char *p;
320b8e80941Smrg
321b8e80941Smrg      if (strcmp(atts[i], "name") == 0) {
322b8e80941Smrg         field->name = ralloc_strdup(field, atts[i + 1]);
323b8e80941Smrg         if (strcmp(field->name, "DWord Length") == 0) {
324b8e80941Smrg            field->parent->dword_length_field = field;
325b8e80941Smrg         }
326b8e80941Smrg      } else if (strcmp(atts[i], "start") == 0) {
327b8e80941Smrg         field->start = strtoul(atts[i + 1], &p, 0);
328b8e80941Smrg      } else if (strcmp(atts[i], "end") == 0) {
329b8e80941Smrg         field->end = strtoul(atts[i + 1], &p, 0);
330b8e80941Smrg      } else if (strcmp(atts[i], "type") == 0) {
331b8e80941Smrg         field->type = string_to_type(ctx, atts[i + 1]);
332b8e80941Smrg      } else if (strcmp(atts[i], "default") == 0 &&
333b8e80941Smrg               field->start >= 16 && field->end <= 31) {
334b8e80941Smrg         field->has_default = true;
335b8e80941Smrg         field->default_value = strtoul(atts[i + 1], &p, 0);
336b8e80941Smrg      }
337b8e80941Smrg   }
338b8e80941Smrg
339b8e80941Smrg   return field;
340b8e80941Smrg}
341b8e80941Smrg
342b8e80941Smrgstatic struct gen_value *
343b8e80941Smrgcreate_value(struct parser_context *ctx, const char **atts)
344b8e80941Smrg{
345b8e80941Smrg   struct gen_value *value = rzalloc(ctx->values, struct gen_value);
346b8e80941Smrg
347b8e80941Smrg   for (int i = 0; atts[i]; i += 2) {
348b8e80941Smrg      if (strcmp(atts[i], "name") == 0)
349b8e80941Smrg         value->name = ralloc_strdup(value, atts[i + 1]);
350b8e80941Smrg      else if (strcmp(atts[i], "value") == 0)
351b8e80941Smrg         value->value = strtoul(atts[i + 1], NULL, 0);
352b8e80941Smrg   }
353b8e80941Smrg
354b8e80941Smrg   return value;
355b8e80941Smrg}
356b8e80941Smrg
357b8e80941Smrgstatic struct gen_field *
358b8e80941Smrgcreate_and_append_field(struct parser_context *ctx,
359b8e80941Smrg                        const char **atts)
360b8e80941Smrg{
361b8e80941Smrg   struct gen_field *field = create_field(ctx, atts);
362b8e80941Smrg   struct gen_field *prev = NULL, *list = ctx->group->fields;
363b8e80941Smrg
364b8e80941Smrg   while (list && field->start > list->start) {
365b8e80941Smrg      prev = list;
366b8e80941Smrg      list = list->next;
367b8e80941Smrg   }
368b8e80941Smrg
369b8e80941Smrg   field->next = list;
370b8e80941Smrg   if (prev == NULL)
371b8e80941Smrg      ctx->group->fields = field;
372b8e80941Smrg   else
373b8e80941Smrg      prev->next = field;
374b8e80941Smrg
375b8e80941Smrg   return field;
376b8e80941Smrg}
377b8e80941Smrg
378b8e80941Smrgstatic void
379b8e80941Smrgstart_element(void *data, const char *element_name, const char **atts)
380b8e80941Smrg{
381b8e80941Smrg   struct parser_context *ctx = data;
382b8e80941Smrg   const char *name = NULL;
383b8e80941Smrg   const char *gen = NULL;
384b8e80941Smrg
385b8e80941Smrg   ctx->loc.line_number = XML_GetCurrentLineNumber(ctx->parser);
386b8e80941Smrg
387b8e80941Smrg   for (int i = 0; atts[i]; i += 2) {
388b8e80941Smrg      if (strcmp(atts[i], "name") == 0)
389b8e80941Smrg         name = atts[i + 1];
390b8e80941Smrg      else if (strcmp(atts[i], "gen") == 0)
391b8e80941Smrg         gen = atts[i + 1];
392b8e80941Smrg   }
393b8e80941Smrg
394b8e80941Smrg   if (strcmp(element_name, "genxml") == 0) {
395b8e80941Smrg      if (name == NULL)
396b8e80941Smrg         fail(&ctx->loc, "no platform name given");
397b8e80941Smrg      if (gen == NULL)
398b8e80941Smrg         fail(&ctx->loc, "no gen given");
399b8e80941Smrg
400b8e80941Smrg      int major, minor;
401b8e80941Smrg      int n = sscanf(gen, "%d.%d", &major, &minor);
402b8e80941Smrg      if (n == 0)
403b8e80941Smrg         fail(&ctx->loc, "invalid gen given: %s", gen);
404b8e80941Smrg      if (n == 1)
405b8e80941Smrg         minor = 0;
406b8e80941Smrg
407b8e80941Smrg      ctx->spec->gen = gen_make_gen(major, minor);
408b8e80941Smrg   } else if (strcmp(element_name, "instruction") == 0) {
409b8e80941Smrg      ctx->group = create_group(ctx, name, atts, NULL, false);
410b8e80941Smrg   } else if (strcmp(element_name, "struct") == 0) {
411b8e80941Smrg      ctx->group = create_group(ctx, name, atts, NULL, true);
412b8e80941Smrg   } else if (strcmp(element_name, "register") == 0) {
413b8e80941Smrg      ctx->group = create_group(ctx, name, atts, NULL, true);
414b8e80941Smrg      get_register_offset(atts, &ctx->group->register_offset);
415b8e80941Smrg   } else if (strcmp(element_name, "group") == 0) {
416b8e80941Smrg      struct gen_group *previous_group = ctx->group;
417b8e80941Smrg      while (previous_group->next)
418b8e80941Smrg         previous_group = previous_group->next;
419b8e80941Smrg
420b8e80941Smrg      struct gen_group *group = create_group(ctx, "", atts, ctx->group, false);
421b8e80941Smrg      previous_group->next = group;
422b8e80941Smrg      ctx->group = group;
423b8e80941Smrg   } else if (strcmp(element_name, "field") == 0) {
424b8e80941Smrg      ctx->last_field = create_and_append_field(ctx, atts);
425b8e80941Smrg   } else if (strcmp(element_name, "enum") == 0) {
426b8e80941Smrg      ctx->enoom = create_enum(ctx, name, atts);
427b8e80941Smrg   } else if (strcmp(element_name, "value") == 0) {
428b8e80941Smrg      if (ctx->n_values >= ctx->n_allocated_values) {
429b8e80941Smrg         ctx->n_allocated_values = MAX2(2, ctx->n_allocated_values * 2);
430b8e80941Smrg         ctx->values = reralloc_array_size(ctx->spec, ctx->values,
431b8e80941Smrg                                           sizeof(struct gen_value *),
432b8e80941Smrg                                           ctx->n_allocated_values);
433b8e80941Smrg      }
434b8e80941Smrg      assert(ctx->n_values < ctx->n_allocated_values);
435b8e80941Smrg      ctx->values[ctx->n_values++] = create_value(ctx, atts);
436b8e80941Smrg   }
437b8e80941Smrg
438b8e80941Smrg}
439b8e80941Smrg
440b8e80941Smrgstatic void
441b8e80941Smrgend_element(void *data, const char *name)
442b8e80941Smrg{
443b8e80941Smrg   struct parser_context *ctx = data;
444b8e80941Smrg   struct gen_spec *spec = ctx->spec;
445b8e80941Smrg
446b8e80941Smrg   if (strcmp(name, "instruction") == 0 ||
447b8e80941Smrg       strcmp(name, "struct") == 0 ||
448b8e80941Smrg       strcmp(name, "register") == 0) {
449b8e80941Smrg      struct gen_group *group = ctx->group;
450b8e80941Smrg      struct gen_field *list = group->fields;
451b8e80941Smrg
452b8e80941Smrg      ctx->group = ctx->group->parent;
453b8e80941Smrg
454b8e80941Smrg      while (list && list->end <= 31) {
455b8e80941Smrg         if (list->start >= 16 && list->has_default) {
456b8e80941Smrg            group->opcode_mask |=
457b8e80941Smrg               mask(list->start % 32, list->end % 32);
458b8e80941Smrg            group->opcode |= list->default_value << list->start;
459b8e80941Smrg         }
460b8e80941Smrg         list = list->next;
461b8e80941Smrg      }
462b8e80941Smrg
463b8e80941Smrg      if (strcmp(name, "instruction") == 0)
464b8e80941Smrg         _mesa_hash_table_insert(spec->commands, group->name, group);
465b8e80941Smrg      else if (strcmp(name, "struct") == 0)
466b8e80941Smrg         _mesa_hash_table_insert(spec->structs, group->name, group);
467b8e80941Smrg      else if (strcmp(name, "register") == 0) {
468b8e80941Smrg         _mesa_hash_table_insert(spec->registers_by_name, group->name, group);
469b8e80941Smrg         _mesa_hash_table_insert(spec->registers_by_offset,
470b8e80941Smrg                                 (void *) (uintptr_t) group->register_offset,
471b8e80941Smrg                                 group);
472b8e80941Smrg      }
473b8e80941Smrg   } else if (strcmp(name, "group") == 0) {
474b8e80941Smrg      ctx->group = ctx->group->parent;
475b8e80941Smrg   } else if (strcmp(name, "field") == 0) {
476b8e80941Smrg      struct gen_field *field = ctx->last_field;
477b8e80941Smrg      ctx->last_field = NULL;
478b8e80941Smrg      field->inline_enum.values = ctx->values;
479b8e80941Smrg      field->inline_enum.nvalues = ctx->n_values;
480b8e80941Smrg      ctx->values = ralloc_array(ctx->spec, struct gen_value*, ctx->n_allocated_values = 2);
481b8e80941Smrg      ctx->n_values = 0;
482b8e80941Smrg   } else if (strcmp(name, "enum") == 0) {
483b8e80941Smrg      struct gen_enum *e = ctx->enoom;
484b8e80941Smrg      e->values = ctx->values;
485b8e80941Smrg      e->nvalues = ctx->n_values;
486b8e80941Smrg      ctx->values = ralloc_array(ctx->spec, struct gen_value*, ctx->n_allocated_values = 2);
487b8e80941Smrg      ctx->n_values = 0;
488b8e80941Smrg      ctx->enoom = NULL;
489b8e80941Smrg      _mesa_hash_table_insert(spec->enums, e->name, e);
490b8e80941Smrg   }
491b8e80941Smrg}
492b8e80941Smrg
493b8e80941Smrgstatic void
494b8e80941Smrgcharacter_data(void *data, const XML_Char *s, int len)
495b8e80941Smrg{
496b8e80941Smrg}
497b8e80941Smrg
498b8e80941Smrgstatic int
499b8e80941Smrgdevinfo_to_gen(const struct gen_device_info *devinfo, bool x10)
500b8e80941Smrg{
501b8e80941Smrg   if (devinfo->is_baytrail || devinfo->is_haswell) {
502b8e80941Smrg      return devinfo->gen * 10 + 5;
503b8e80941Smrg   }
504b8e80941Smrg
505b8e80941Smrg   return x10 ? devinfo->gen * 10 : devinfo->gen;
506b8e80941Smrg}
507b8e80941Smrg
508b8e80941Smrgstatic uint32_t zlib_inflate(const void *compressed_data,
509b8e80941Smrg                             uint32_t compressed_len,
510b8e80941Smrg                             void **out_ptr)
511b8e80941Smrg{
512b8e80941Smrg   struct z_stream_s zstream;
513b8e80941Smrg   void *out;
514b8e80941Smrg
515b8e80941Smrg   memset(&zstream, 0, sizeof(zstream));
516b8e80941Smrg
517b8e80941Smrg   zstream.next_in = (unsigned char *)compressed_data;
518b8e80941Smrg   zstream.avail_in = compressed_len;
519b8e80941Smrg
520b8e80941Smrg   if (inflateInit(&zstream) != Z_OK)
521b8e80941Smrg      return 0;
522b8e80941Smrg
523b8e80941Smrg   out = malloc(4096);
524b8e80941Smrg   zstream.next_out = out;
525b8e80941Smrg   zstream.avail_out = 4096;
526b8e80941Smrg
527b8e80941Smrg   do {
528b8e80941Smrg      switch (inflate(&zstream, Z_SYNC_FLUSH)) {
529b8e80941Smrg      case Z_STREAM_END:
530b8e80941Smrg         goto end;
531b8e80941Smrg      case Z_OK:
532b8e80941Smrg         break;
533b8e80941Smrg      default:
534b8e80941Smrg         inflateEnd(&zstream);
535b8e80941Smrg         return 0;
536b8e80941Smrg      }
537b8e80941Smrg
538b8e80941Smrg      if (zstream.avail_out)
539b8e80941Smrg         break;
540b8e80941Smrg
541b8e80941Smrg      out = realloc(out, 2*zstream.total_out);
542b8e80941Smrg      if (out == NULL) {
543b8e80941Smrg         inflateEnd(&zstream);
544b8e80941Smrg         return 0;
545b8e80941Smrg      }
546b8e80941Smrg
547b8e80941Smrg      zstream.next_out = (unsigned char *)out + zstream.total_out;
548b8e80941Smrg      zstream.avail_out = zstream.total_out;
549b8e80941Smrg   } while (1);
550b8e80941Smrg end:
551b8e80941Smrg   inflateEnd(&zstream);
552b8e80941Smrg   *out_ptr = out;
553b8e80941Smrg   return zstream.total_out;
554b8e80941Smrg}
555b8e80941Smrg
556b8e80941Smrgstatic uint32_t _hash_uint32(const void *key)
557b8e80941Smrg{
558b8e80941Smrg   return (uint32_t) (uintptr_t) key;
559b8e80941Smrg}
560b8e80941Smrg
561b8e80941Smrgstatic struct gen_spec *
562b8e80941Smrggen_spec_init(void)
563b8e80941Smrg{
564b8e80941Smrg   struct gen_spec *spec;
565b8e80941Smrg   spec = rzalloc(NULL, struct gen_spec);
566b8e80941Smrg   if (spec == NULL)
567b8e80941Smrg      return NULL;
568b8e80941Smrg
569b8e80941Smrg   spec->commands =
570b8e80941Smrg      _mesa_hash_table_create(spec, _mesa_hash_string, _mesa_key_string_equal);
571b8e80941Smrg   spec->structs =
572b8e80941Smrg      _mesa_hash_table_create(spec, _mesa_hash_string, _mesa_key_string_equal);
573b8e80941Smrg   spec->registers_by_name =
574b8e80941Smrg      _mesa_hash_table_create(spec, _mesa_hash_string, _mesa_key_string_equal);
575b8e80941Smrg   spec->registers_by_offset =
576b8e80941Smrg      _mesa_hash_table_create(spec, _hash_uint32, _mesa_key_pointer_equal);
577b8e80941Smrg   spec->enums =
578b8e80941Smrg      _mesa_hash_table_create(spec, _mesa_hash_string, _mesa_key_string_equal);
579b8e80941Smrg   spec->access_cache =
580b8e80941Smrg      _mesa_hash_table_create(spec, _mesa_hash_string, _mesa_key_string_equal);
581b8e80941Smrg
582b8e80941Smrg   return spec;
583b8e80941Smrg}
584b8e80941Smrg
585b8e80941Smrgstruct gen_spec *
586b8e80941Smrggen_spec_load(const struct gen_device_info *devinfo)
587b8e80941Smrg{
588b8e80941Smrg   struct parser_context ctx;
589b8e80941Smrg   void *buf;
590b8e80941Smrg   uint8_t *text_data = NULL;
591b8e80941Smrg   uint32_t text_offset = 0, text_length = 0;
592b8e80941Smrg   MAYBE_UNUSED uint32_t total_length;
593b8e80941Smrg   uint32_t gen_10 = devinfo_to_gen(devinfo, true);
594b8e80941Smrg
595b8e80941Smrg   for (int i = 0; i < ARRAY_SIZE(genxml_files_table); i++) {
596b8e80941Smrg      if (genxml_files_table[i].gen_10 == gen_10) {
597b8e80941Smrg         text_offset = genxml_files_table[i].offset;
598b8e80941Smrg         text_length = genxml_files_table[i].length;
599b8e80941Smrg         break;
600b8e80941Smrg      }
601b8e80941Smrg   }
602b8e80941Smrg
603b8e80941Smrg   if (text_length == 0) {
604b8e80941Smrg      fprintf(stderr, "unable to find gen (%u) data\n", gen_10);
605b8e80941Smrg      return NULL;
606b8e80941Smrg   }
607b8e80941Smrg
608b8e80941Smrg   memset(&ctx, 0, sizeof ctx);
609b8e80941Smrg   ctx.parser = XML_ParserCreate(NULL);
610b8e80941Smrg   XML_SetUserData(ctx.parser, &ctx);
611b8e80941Smrg   if (ctx.parser == NULL) {
612b8e80941Smrg      fprintf(stderr, "failed to create parser\n");
613b8e80941Smrg      return NULL;
614b8e80941Smrg   }
615b8e80941Smrg
616b8e80941Smrg   XML_SetElementHandler(ctx.parser, start_element, end_element);
617b8e80941Smrg   XML_SetCharacterDataHandler(ctx.parser, character_data);
618b8e80941Smrg
619b8e80941Smrg   ctx.spec = gen_spec_init();
620b8e80941Smrg   if (ctx.spec == NULL) {
621b8e80941Smrg      fprintf(stderr, "Failed to create gen_spec\n");
622b8e80941Smrg      return NULL;
623b8e80941Smrg   }
624b8e80941Smrg
625b8e80941Smrg   total_length = zlib_inflate(compress_genxmls,
626b8e80941Smrg                               sizeof(compress_genxmls),
627b8e80941Smrg                               (void **) &text_data);
628b8e80941Smrg   assert(text_offset + text_length <= total_length);
629b8e80941Smrg
630b8e80941Smrg   buf = XML_GetBuffer(ctx.parser, text_length);
631b8e80941Smrg   memcpy(buf, &text_data[text_offset], text_length);
632b8e80941Smrg
633b8e80941Smrg   if (XML_ParseBuffer(ctx.parser, text_length, true) == 0) {
634b8e80941Smrg      fprintf(stderr,
635b8e80941Smrg              "Error parsing XML at line %ld col %ld byte %ld/%u: %s\n",
636b8e80941Smrg              XML_GetCurrentLineNumber(ctx.parser),
637b8e80941Smrg              XML_GetCurrentColumnNumber(ctx.parser),
638b8e80941Smrg              XML_GetCurrentByteIndex(ctx.parser), text_length,
639b8e80941Smrg              XML_ErrorString(XML_GetErrorCode(ctx.parser)));
640b8e80941Smrg      XML_ParserFree(ctx.parser);
641b8e80941Smrg      free(text_data);
642b8e80941Smrg      return NULL;
643b8e80941Smrg   }
644b8e80941Smrg
645b8e80941Smrg   XML_ParserFree(ctx.parser);
646b8e80941Smrg   free(text_data);
647b8e80941Smrg
648b8e80941Smrg   return ctx.spec;
649b8e80941Smrg}
650b8e80941Smrg
651b8e80941Smrgstruct gen_spec *
652b8e80941Smrggen_spec_load_from_path(const struct gen_device_info *devinfo,
653b8e80941Smrg                        const char *path)
654b8e80941Smrg{
655b8e80941Smrg   struct parser_context ctx;
656b8e80941Smrg   size_t len, filename_len = strlen(path) + 20;
657b8e80941Smrg   char *filename = malloc(filename_len);
658b8e80941Smrg   void *buf;
659b8e80941Smrg   FILE *input;
660b8e80941Smrg
661b8e80941Smrg   len = snprintf(filename, filename_len, "%s/gen%i.xml",
662b8e80941Smrg                  path, devinfo_to_gen(devinfo, false));
663b8e80941Smrg   assert(len < filename_len);
664b8e80941Smrg
665b8e80941Smrg   input = fopen(filename, "r");
666b8e80941Smrg   if (input == NULL) {
667b8e80941Smrg      fprintf(stderr, "failed to open xml description\n");
668b8e80941Smrg      free(filename);
669b8e80941Smrg      return NULL;
670b8e80941Smrg   }
671b8e80941Smrg
672b8e80941Smrg   memset(&ctx, 0, sizeof ctx);
673b8e80941Smrg   ctx.parser = XML_ParserCreate(NULL);
674b8e80941Smrg   XML_SetUserData(ctx.parser, &ctx);
675b8e80941Smrg   if (ctx.parser == NULL) {
676b8e80941Smrg      fprintf(stderr, "failed to create parser\n");
677b8e80941Smrg      fclose(input);
678b8e80941Smrg      free(filename);
679b8e80941Smrg      return NULL;
680b8e80941Smrg   }
681b8e80941Smrg
682b8e80941Smrg   XML_SetElementHandler(ctx.parser, start_element, end_element);
683b8e80941Smrg   XML_SetCharacterDataHandler(ctx.parser, character_data);
684b8e80941Smrg   ctx.loc.filename = filename;
685b8e80941Smrg
686b8e80941Smrg   ctx.spec = gen_spec_init();
687b8e80941Smrg   if (ctx.spec == NULL) {
688b8e80941Smrg      fprintf(stderr, "Failed to create gen_spec\n");
689b8e80941Smrg      goto end;
690b8e80941Smrg   }
691b8e80941Smrg
692b8e80941Smrg   do {
693b8e80941Smrg      buf = XML_GetBuffer(ctx.parser, XML_BUFFER_SIZE);
694b8e80941Smrg      len = fread(buf, 1, XML_BUFFER_SIZE, input);
695b8e80941Smrg      if (ferror(input)) {
696b8e80941Smrg         fprintf(stderr, "fread: %m\n");
697b8e80941Smrg         gen_spec_destroy(ctx.spec);
698b8e80941Smrg         ctx.spec = NULL;
699b8e80941Smrg         goto end;
700b8e80941Smrg      } else if (feof(input))
701b8e80941Smrg         goto end;
702b8e80941Smrg
703b8e80941Smrg      if (XML_ParseBuffer(ctx.parser, len, len == 0) == 0) {
704b8e80941Smrg         fprintf(stderr,
705b8e80941Smrg                 "Error parsing XML at line %ld col %ld: %s\n",
706b8e80941Smrg                 XML_GetCurrentLineNumber(ctx.parser),
707b8e80941Smrg                 XML_GetCurrentColumnNumber(ctx.parser),
708b8e80941Smrg                 XML_ErrorString(XML_GetErrorCode(ctx.parser)));
709b8e80941Smrg         gen_spec_destroy(ctx.spec);
710b8e80941Smrg         ctx.spec = NULL;
711b8e80941Smrg         goto end;
712b8e80941Smrg      }
713b8e80941Smrg   } while (len > 0);
714b8e80941Smrg
715b8e80941Smrg end:
716b8e80941Smrg   XML_ParserFree(ctx.parser);
717b8e80941Smrg
718b8e80941Smrg   fclose(input);
719b8e80941Smrg   free(filename);
720b8e80941Smrg
721b8e80941Smrg   /* free ctx.spec if genxml is empty */
722b8e80941Smrg   if (ctx.spec && _mesa_hash_table_num_entries(ctx.spec->commands) == 0) {
723b8e80941Smrg      gen_spec_destroy(ctx.spec);
724b8e80941Smrg      return NULL;
725b8e80941Smrg   }
726b8e80941Smrg
727b8e80941Smrg   return ctx.spec;
728b8e80941Smrg}
729b8e80941Smrg
730b8e80941Smrgvoid gen_spec_destroy(struct gen_spec *spec)
731b8e80941Smrg{
732b8e80941Smrg   ralloc_free(spec);
733b8e80941Smrg}
734b8e80941Smrg
735b8e80941Smrgstruct gen_group *
736b8e80941Smrggen_spec_find_instruction(struct gen_spec *spec,
737b8e80941Smrg                          enum drm_i915_gem_engine_class engine,
738b8e80941Smrg                          const uint32_t *p)
739b8e80941Smrg{
740b8e80941Smrg   hash_table_foreach(spec->commands, entry) {
741b8e80941Smrg      struct gen_group *command = entry->data;
742b8e80941Smrg      uint32_t opcode = *p & command->opcode_mask;
743b8e80941Smrg      if ((command->engine_mask & I915_ENGINE_CLASS_TO_MASK(engine)) &&
744b8e80941Smrg           opcode == command->opcode)
745b8e80941Smrg         return command;
746b8e80941Smrg   }
747b8e80941Smrg
748b8e80941Smrg   return NULL;
749b8e80941Smrg}
750b8e80941Smrg
751b8e80941Smrgstruct gen_field *
752b8e80941Smrggen_group_find_field(struct gen_group *group, const char *name)
753b8e80941Smrg{
754b8e80941Smrg   char path[256];
755b8e80941Smrg   snprintf(path, sizeof(path), "%s/%s", group->name, name);
756b8e80941Smrg
757b8e80941Smrg   struct gen_spec *spec = group->spec;
758b8e80941Smrg   struct hash_entry *entry = _mesa_hash_table_search(spec->access_cache,
759b8e80941Smrg                                                      path);
760b8e80941Smrg   if (entry)
761b8e80941Smrg      return entry->data;
762b8e80941Smrg
763b8e80941Smrg   struct gen_field *field = group->fields;
764b8e80941Smrg   while (field) {
765b8e80941Smrg      if (strcmp(field->name, name) == 0) {
766b8e80941Smrg         _mesa_hash_table_insert(spec->access_cache,
767b8e80941Smrg                                 ralloc_strdup(spec, path),
768b8e80941Smrg                                 field);
769b8e80941Smrg         return field;
770b8e80941Smrg      }
771b8e80941Smrg      field = field->next;
772b8e80941Smrg   }
773b8e80941Smrg
774b8e80941Smrg   return NULL;
775b8e80941Smrg}
776b8e80941Smrg
777b8e80941Smrgint
778b8e80941Smrggen_group_get_length(struct gen_group *group, const uint32_t *p)
779b8e80941Smrg{
780b8e80941Smrg   if (group) {
781b8e80941Smrg      if (group->fixed_length)
782b8e80941Smrg         return group->dw_length;
783b8e80941Smrg      else {
784b8e80941Smrg         struct gen_field *field = group->dword_length_field;
785b8e80941Smrg         if (field) {
786b8e80941Smrg            return field_value(p[0], field->start, field->end) + group->bias;
787b8e80941Smrg         }
788b8e80941Smrg      }
789b8e80941Smrg   }
790b8e80941Smrg
791b8e80941Smrg   uint32_t h = p[0];
792b8e80941Smrg   uint32_t type = field_value(h, 29, 31);
793b8e80941Smrg
794b8e80941Smrg   switch (type) {
795b8e80941Smrg   case 0: /* MI */ {
796b8e80941Smrg      uint32_t opcode = field_value(h, 23, 28);
797b8e80941Smrg      if (opcode < 16)
798b8e80941Smrg         return 1;
799b8e80941Smrg      else
800b8e80941Smrg         return field_value(h, 0, 7) + 2;
801b8e80941Smrg      break;
802b8e80941Smrg   }
803b8e80941Smrg
804b8e80941Smrg   case 2: /* BLT */ {
805b8e80941Smrg      return field_value(h, 0, 7) + 2;
806b8e80941Smrg   }
807b8e80941Smrg
808b8e80941Smrg   case 3: /* Render */ {
809b8e80941Smrg      uint32_t subtype = field_value(h, 27, 28);
810b8e80941Smrg      uint32_t opcode = field_value(h, 24, 26);
811b8e80941Smrg      uint16_t whole_opcode = field_value(h, 16, 31);
812b8e80941Smrg      switch (subtype) {
813b8e80941Smrg      case 0:
814b8e80941Smrg         if (whole_opcode == 0x6104 /* PIPELINE_SELECT_965 */)
815b8e80941Smrg            return 1;
816b8e80941Smrg         else if (opcode < 2)
817b8e80941Smrg            return field_value(h, 0, 7) + 2;
818b8e80941Smrg         else
819b8e80941Smrg            return -1;
820b8e80941Smrg      case 1:
821b8e80941Smrg         if (opcode < 2)
822b8e80941Smrg            return 1;
823b8e80941Smrg         else
824b8e80941Smrg            return -1;
825b8e80941Smrg      case 2: {
826b8e80941Smrg         if (opcode == 0)
827b8e80941Smrg            return field_value(h, 0, 7) + 2;
828b8e80941Smrg         else if (opcode < 3)
829b8e80941Smrg            return field_value(h, 0, 15) + 2;
830b8e80941Smrg         else
831b8e80941Smrg            return -1;
832b8e80941Smrg      }
833b8e80941Smrg      case 3:
834b8e80941Smrg         if (whole_opcode == 0x780b)
835b8e80941Smrg            return 1;
836b8e80941Smrg         else if (opcode < 4)
837b8e80941Smrg            return field_value(h, 0, 7) + 2;
838b8e80941Smrg         else
839b8e80941Smrg            return -1;
840b8e80941Smrg      }
841b8e80941Smrg   }
842b8e80941Smrg   }
843b8e80941Smrg
844b8e80941Smrg   return -1;
845b8e80941Smrg}
846b8e80941Smrg
847b8e80941Smrgstatic const char *
848b8e80941Smrggen_get_enum_name(struct gen_enum *e, uint64_t value)
849b8e80941Smrg{
850b8e80941Smrg   for (int i = 0; i < e->nvalues; i++) {
851b8e80941Smrg      if (e->values[i]->value == value) {
852b8e80941Smrg         return e->values[i]->name;
853b8e80941Smrg      }
854b8e80941Smrg   }
855b8e80941Smrg   return NULL;
856b8e80941Smrg}
857b8e80941Smrg
858b8e80941Smrgstatic bool
859b8e80941Smrgiter_more_fields(const struct gen_field_iterator *iter)
860b8e80941Smrg{
861b8e80941Smrg   return iter->field != NULL && iter->field->next != NULL;
862b8e80941Smrg}
863b8e80941Smrg
864b8e80941Smrgstatic uint32_t
865b8e80941Smrgiter_group_offset_bits(const struct gen_field_iterator *iter,
866b8e80941Smrg                       uint32_t group_iter)
867b8e80941Smrg{
868b8e80941Smrg   return iter->group->group_offset + (group_iter * iter->group->group_size);
869b8e80941Smrg}
870b8e80941Smrg
871b8e80941Smrgstatic bool
872b8e80941Smrgiter_more_groups(const struct gen_field_iterator *iter)
873b8e80941Smrg{
874b8e80941Smrg   if (iter->group->variable) {
875b8e80941Smrg      int length = gen_group_get_length(iter->group, iter->p);
876b8e80941Smrg      assert(length >= 0 && "error the length is unknown!");
877b8e80941Smrg      return iter_group_offset_bits(iter, iter->group_iter + 1) <
878b8e80941Smrg              (length * 32);
879b8e80941Smrg   } else {
880b8e80941Smrg      return (iter->group_iter + 1) < iter->group->group_count ||
881b8e80941Smrg         iter->group->next != NULL;
882b8e80941Smrg   }
883b8e80941Smrg}
884b8e80941Smrg
885b8e80941Smrgstatic void
886b8e80941Smrgiter_start_field(struct gen_field_iterator *iter, struct gen_field *field)
887b8e80941Smrg{
888b8e80941Smrg   iter->field = field;
889b8e80941Smrg
890b8e80941Smrg   int group_member_offset = iter_group_offset_bits(iter, iter->group_iter);
891b8e80941Smrg
892b8e80941Smrg   iter->start_bit = group_member_offset + iter->field->start;
893b8e80941Smrg   iter->end_bit = group_member_offset + iter->field->end;
894b8e80941Smrg   iter->struct_desc = NULL;
895b8e80941Smrg}
896b8e80941Smrg
897b8e80941Smrgstatic void
898b8e80941Smrgiter_advance_group(struct gen_field_iterator *iter)
899b8e80941Smrg{
900b8e80941Smrg   if (iter->group->variable)
901b8e80941Smrg      iter->group_iter++;
902b8e80941Smrg   else {
903b8e80941Smrg      if ((iter->group_iter + 1) < iter->group->group_count) {
904b8e80941Smrg         iter->group_iter++;
905b8e80941Smrg      } else {
906b8e80941Smrg         iter->group = iter->group->next;
907b8e80941Smrg         iter->group_iter = 0;
908b8e80941Smrg      }
909b8e80941Smrg   }
910b8e80941Smrg
911b8e80941Smrg   iter_start_field(iter, iter->group->fields);
912b8e80941Smrg}
913b8e80941Smrg
914b8e80941Smrgstatic bool
915b8e80941Smrgiter_advance_field(struct gen_field_iterator *iter)
916b8e80941Smrg{
917b8e80941Smrg   if (iter_more_fields(iter)) {
918b8e80941Smrg      iter_start_field(iter, iter->field->next);
919b8e80941Smrg   } else {
920b8e80941Smrg      if (!iter_more_groups(iter))
921b8e80941Smrg         return false;
922b8e80941Smrg
923b8e80941Smrg      iter_advance_group(iter);
924b8e80941Smrg   }
925b8e80941Smrg   return true;
926b8e80941Smrg}
927b8e80941Smrg
928b8e80941Smrgstatic bool
929b8e80941Smrgiter_decode_field_raw(struct gen_field_iterator *iter, uint64_t *qw)
930b8e80941Smrg{
931b8e80941Smrg   *qw = 0;
932b8e80941Smrg
933b8e80941Smrg   int field_start = iter->p_bit + iter->start_bit;
934b8e80941Smrg   int field_end = iter->p_bit + iter->end_bit;
935b8e80941Smrg
936b8e80941Smrg   const uint32_t *p = iter->p + (iter->start_bit / 32);
937b8e80941Smrg   if (iter->p_end && p >= iter->p_end)
938b8e80941Smrg      return false;
939b8e80941Smrg
940b8e80941Smrg   if ((field_end - field_start) > 32) {
941b8e80941Smrg      if (!iter->p_end || (p + 1) < iter->p_end)
942b8e80941Smrg         *qw = ((uint64_t) p[1]) << 32;
943b8e80941Smrg      *qw |= p[0];
944b8e80941Smrg   } else
945b8e80941Smrg      *qw = p[0];
946b8e80941Smrg
947b8e80941Smrg   *qw = field_value(*qw, field_start, field_end);
948b8e80941Smrg
949b8e80941Smrg   /* Address & offset types have to be aligned to dwords, their start bit is
950b8e80941Smrg    * a reminder of the alignment requirement.
951b8e80941Smrg    */
952b8e80941Smrg   if (iter->field->type.kind == GEN_TYPE_ADDRESS ||
953b8e80941Smrg       iter->field->type.kind == GEN_TYPE_OFFSET)
954b8e80941Smrg      *qw <<= field_start % 32;
955b8e80941Smrg
956b8e80941Smrg   return true;
957b8e80941Smrg}
958b8e80941Smrg
959b8e80941Smrgstatic bool
960b8e80941Smrgiter_decode_field(struct gen_field_iterator *iter)
961b8e80941Smrg{
962b8e80941Smrg   union {
963b8e80941Smrg      uint64_t qw;
964b8e80941Smrg      float f;
965b8e80941Smrg   } v;
966b8e80941Smrg
967b8e80941Smrg   if (iter->field->name)
968b8e80941Smrg      snprintf(iter->name, sizeof(iter->name), "%s", iter->field->name);
969b8e80941Smrg   else
970b8e80941Smrg      memset(iter->name, 0, sizeof(iter->name));
971b8e80941Smrg
972b8e80941Smrg   memset(&v, 0, sizeof(v));
973b8e80941Smrg
974b8e80941Smrg   if (!iter_decode_field_raw(iter, &iter->raw_value))
975b8e80941Smrg      return false;
976b8e80941Smrg
977b8e80941Smrg   const char *enum_name = NULL;
978b8e80941Smrg
979b8e80941Smrg   v.qw = iter->raw_value;
980b8e80941Smrg   switch (iter->field->type.kind) {
981b8e80941Smrg   case GEN_TYPE_UNKNOWN:
982b8e80941Smrg   case GEN_TYPE_INT: {
983b8e80941Smrg      snprintf(iter->value, sizeof(iter->value), "%"PRId64, v.qw);
984b8e80941Smrg      enum_name = gen_get_enum_name(&iter->field->inline_enum, v.qw);
985b8e80941Smrg      break;
986b8e80941Smrg   }
987b8e80941Smrg   case GEN_TYPE_UINT: {
988b8e80941Smrg      snprintf(iter->value, sizeof(iter->value), "%"PRIu64, v.qw);
989b8e80941Smrg      enum_name = gen_get_enum_name(&iter->field->inline_enum, v.qw);
990b8e80941Smrg      break;
991b8e80941Smrg   }
992b8e80941Smrg   case GEN_TYPE_BOOL: {
993b8e80941Smrg      const char *true_string =
994b8e80941Smrg         iter->print_colors ? "\e[0;35mtrue\e[0m" : "true";
995b8e80941Smrg      snprintf(iter->value, sizeof(iter->value), "%s",
996b8e80941Smrg               v.qw ? true_string : "false");
997b8e80941Smrg      break;
998b8e80941Smrg   }
999b8e80941Smrg   case GEN_TYPE_FLOAT:
1000b8e80941Smrg      snprintf(iter->value, sizeof(iter->value), "%f", v.f);
1001b8e80941Smrg      break;
1002b8e80941Smrg   case GEN_TYPE_ADDRESS:
1003b8e80941Smrg   case GEN_TYPE_OFFSET:
1004b8e80941Smrg      snprintf(iter->value, sizeof(iter->value), "0x%08"PRIx64, v.qw);
1005b8e80941Smrg      break;
1006b8e80941Smrg   case GEN_TYPE_STRUCT:
1007b8e80941Smrg      snprintf(iter->value, sizeof(iter->value), "<struct %s>",
1008b8e80941Smrg               iter->field->type.gen_struct->name);
1009b8e80941Smrg      iter->struct_desc =
1010b8e80941Smrg         gen_spec_find_struct(iter->group->spec,
1011b8e80941Smrg                              iter->field->type.gen_struct->name);
1012b8e80941Smrg      break;
1013b8e80941Smrg   case GEN_TYPE_UFIXED:
1014b8e80941Smrg      snprintf(iter->value, sizeof(iter->value), "%f",
1015b8e80941Smrg               (float) v.qw / (1 << iter->field->type.f));
1016b8e80941Smrg      break;
1017b8e80941Smrg   case GEN_TYPE_SFIXED: {
1018b8e80941Smrg      /* Sign extend before converting */
1019b8e80941Smrg      int bits = iter->field->type.i + iter->field->type.f + 1;
1020b8e80941Smrg      int64_t v_sign_extend = ((int64_t)(v.qw << (64 - bits))) >> (64 - bits);
1021b8e80941Smrg      snprintf(iter->value, sizeof(iter->value), "%f",
1022b8e80941Smrg               (float) v_sign_extend / (1 << iter->field->type.f));
1023b8e80941Smrg      break;
1024b8e80941Smrg   }
1025b8e80941Smrg   case GEN_TYPE_MBO:
1026b8e80941Smrg       break;
1027b8e80941Smrg   case GEN_TYPE_ENUM: {
1028b8e80941Smrg      snprintf(iter->value, sizeof(iter->value), "%"PRId64, v.qw);
1029b8e80941Smrg      enum_name = gen_get_enum_name(iter->field->type.gen_enum, v.qw);
1030b8e80941Smrg      break;
1031b8e80941Smrg   }
1032b8e80941Smrg   }
1033b8e80941Smrg
1034b8e80941Smrg   if (strlen(iter->group->name) == 0) {
1035b8e80941Smrg      int length = strlen(iter->name);
1036b8e80941Smrg      snprintf(iter->name + length, sizeof(iter->name) - length,
1037b8e80941Smrg               "[%i]", iter->group_iter);
1038b8e80941Smrg   }
1039b8e80941Smrg
1040b8e80941Smrg   if (enum_name) {
1041b8e80941Smrg      int length = strlen(iter->value);
1042b8e80941Smrg      snprintf(iter->value + length, sizeof(iter->value) - length,
1043b8e80941Smrg               " (%s)", enum_name);
1044b8e80941Smrg   } else if (strcmp(iter->name, "Surface Format") == 0 ||
1045b8e80941Smrg              strcmp(iter->name, "Source Element Format") == 0) {
1046b8e80941Smrg      if (isl_format_is_valid((enum isl_format)v.qw)) {
1047b8e80941Smrg         const char *fmt_name = isl_format_get_name((enum isl_format)v.qw);
1048b8e80941Smrg         int length = strlen(iter->value);
1049b8e80941Smrg         snprintf(iter->value + length, sizeof(iter->value) - length,
1050b8e80941Smrg                  " (%s)", fmt_name);
1051b8e80941Smrg      }
1052b8e80941Smrg   }
1053b8e80941Smrg
1054b8e80941Smrg   return true;
1055b8e80941Smrg}
1056b8e80941Smrg
1057b8e80941Smrgvoid
1058b8e80941Smrggen_field_iterator_init(struct gen_field_iterator *iter,
1059b8e80941Smrg                        struct gen_group *group,
1060b8e80941Smrg                        const uint32_t *p, int p_bit,
1061b8e80941Smrg                        bool print_colors)
1062b8e80941Smrg{
1063b8e80941Smrg   memset(iter, 0, sizeof(*iter));
1064b8e80941Smrg
1065b8e80941Smrg   iter->group = group;
1066b8e80941Smrg   iter->p = p;
1067b8e80941Smrg   iter->p_bit = p_bit;
1068b8e80941Smrg
1069b8e80941Smrg   int length = gen_group_get_length(iter->group, iter->p);
1070b8e80941Smrg   assert(length >= 0 && "error the length is unknown!");
1071b8e80941Smrg   iter->p_end = length >= 0 ? &p[length] : NULL;
1072b8e80941Smrg   iter->print_colors = print_colors;
1073b8e80941Smrg}
1074b8e80941Smrg
1075b8e80941Smrgbool
1076b8e80941Smrggen_field_iterator_next(struct gen_field_iterator *iter)
1077b8e80941Smrg{
1078b8e80941Smrg   /* Initial condition */
1079b8e80941Smrg   if (!iter->field) {
1080b8e80941Smrg      if (iter->group->fields)
1081b8e80941Smrg         iter_start_field(iter, iter->group->fields);
1082b8e80941Smrg      else
1083b8e80941Smrg         iter_start_field(iter, iter->group->next->fields);
1084b8e80941Smrg
1085b8e80941Smrg      bool result = iter_decode_field(iter);
1086b8e80941Smrg      if (!result && iter->p_end) {
1087b8e80941Smrg         /* We're dealing with a non empty struct of length=0 (BLEND_STATE on
1088b8e80941Smrg          * Gen 7.5)
1089b8e80941Smrg          */
1090b8e80941Smrg         assert(iter->group->dw_length == 0);
1091b8e80941Smrg      }
1092b8e80941Smrg
1093b8e80941Smrg      return result;
1094b8e80941Smrg   }
1095b8e80941Smrg
1096b8e80941Smrg   if (!iter_advance_field(iter))
1097b8e80941Smrg      return false;
1098b8e80941Smrg
1099b8e80941Smrg   if (!iter_decode_field(iter))
1100b8e80941Smrg      return false;
1101b8e80941Smrg
1102b8e80941Smrg   return true;
1103b8e80941Smrg}
1104b8e80941Smrg
1105b8e80941Smrgstatic void
1106b8e80941Smrgprint_dword_header(FILE *outfile,
1107b8e80941Smrg                   struct gen_field_iterator *iter,
1108b8e80941Smrg                   uint64_t offset, uint32_t dword)
1109b8e80941Smrg{
1110b8e80941Smrg   fprintf(outfile, "0x%08"PRIx64":  0x%08x : Dword %d\n",
1111b8e80941Smrg           offset + 4 * dword, iter->p[dword], dword);
1112b8e80941Smrg}
1113b8e80941Smrg
1114b8e80941Smrgbool
1115b8e80941Smrggen_field_is_header(struct gen_field *field)
1116b8e80941Smrg{
1117b8e80941Smrg   uint32_t bits;
1118b8e80941Smrg
1119b8e80941Smrg   if (field->start >= 32)
1120b8e80941Smrg      return false;
1121b8e80941Smrg
1122b8e80941Smrg   bits = (1U << (field->end - field->start + 1)) - 1;
1123b8e80941Smrg   bits <<= field->start;
1124b8e80941Smrg
1125b8e80941Smrg   return (field->parent->opcode_mask & bits) != 0;
1126b8e80941Smrg}
1127b8e80941Smrg
1128b8e80941Smrgvoid
1129b8e80941Smrggen_print_group(FILE *outfile, struct gen_group *group, uint64_t offset,
1130b8e80941Smrg                const uint32_t *p, int p_bit, bool color)
1131b8e80941Smrg{
1132b8e80941Smrg   struct gen_field_iterator iter;
1133b8e80941Smrg   int last_dword = -1;
1134b8e80941Smrg
1135b8e80941Smrg   gen_field_iterator_init(&iter, group, p, p_bit, color);
1136b8e80941Smrg   while (gen_field_iterator_next(&iter)) {
1137b8e80941Smrg      int iter_dword = iter.end_bit / 32;
1138b8e80941Smrg      if (last_dword != iter_dword) {
1139b8e80941Smrg         for (int i = last_dword + 1; i <= iter_dword; i++)
1140b8e80941Smrg            print_dword_header(outfile, &iter, offset, i);
1141b8e80941Smrg         last_dword = iter_dword;
1142b8e80941Smrg      }
1143b8e80941Smrg      if (!gen_field_is_header(iter.field)) {
1144b8e80941Smrg         fprintf(outfile, "    %s: %s\n", iter.name, iter.value);
1145b8e80941Smrg         if (iter.struct_desc) {
1146b8e80941Smrg            int struct_dword = iter.start_bit / 32;
1147b8e80941Smrg            uint64_t struct_offset = offset + 4 * struct_dword;
1148b8e80941Smrg            gen_print_group(outfile, iter.struct_desc, struct_offset,
1149b8e80941Smrg                            &p[struct_dword], iter.start_bit % 32, color);
1150b8e80941Smrg         }
1151b8e80941Smrg      }
1152b8e80941Smrg   }
1153b8e80941Smrg}
1154