2 * Copyright © 2016 Intel Corporation
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
32 #include <util/macros.h>
36 #include "genxml/gen6_xml.h"
37 #include "genxml/gen7_xml.h"
38 #include "genxml/gen75_xml.h"
39 #include "genxml/gen8_xml.h"
40 #include "genxml/gen9_xml.h"
42 #define XML_BUFFER_SIZE 4096
44 #define MAKE_GEN(major, minor) ( ((major) << 8) | (minor) )
50 struct gen_group
*commands
[256];
52 struct gen_group
*structs
[256];
54 struct gen_group
*registers
[256];
62 struct parser_context
{
68 struct gen_group
*group
;
71 struct gen_field
*fields
[128];
73 struct gen_spec
*spec
;
77 gen_group_get_name(struct gen_group
*group
)
83 gen_group_get_opcode(struct gen_group
*group
)
89 gen_spec_find_struct(struct gen_spec
*spec
, const char *name
)
91 for (int i
= 0; i
< spec
->nstructs
; i
++)
92 if (strcmp(spec
->structs
[i
]->name
, name
) == 0)
93 return spec
->structs
[i
];
99 gen_spec_find_register(struct gen_spec
*spec
, uint32_t offset
)
101 for (int i
= 0; i
< spec
->nregisters
; i
++)
102 if (spec
->registers
[i
]->register_offset
== offset
)
103 return spec
->registers
[i
];
109 gen_spec_get_gen(struct gen_spec
*spec
)
114 static void __attribute__((noreturn
))
115 fail(struct location
*loc
, const char *msg
, ...)
120 fprintf(stderr
, "%s:%d: error: ",
121 loc
->filename
, loc
->line_number
);
122 vfprintf(stderr
, msg
, ap
);
123 fprintf(stderr
, "\n");
129 fail_on_null(void *p
)
132 fprintf(stderr
, "aubinator: out of memory\n");
140 xstrdup(const char *s
)
142 return fail_on_null(strdup(s
));
154 return fail_on_null(zalloc(s
));
157 static struct gen_group
*
158 create_group(struct parser_context
*ctx
, const char *name
, const char **atts
)
160 struct gen_group
*group
;
162 group
= xzalloc(sizeof(*group
));
164 group
->name
= xstrdup(name
);
166 group
->group_offset
= 0;
167 group
->group_count
= 0;
173 get_group_offset_count(struct parser_context
*ctx
, const char *name
,
174 const char **atts
, uint32_t *offset
, uint32_t *count
)
179 for (i
= 0; atts
[i
]; i
+= 2) {
180 if (strcmp(atts
[i
], "count") == 0)
181 *count
= strtoul(atts
[i
+ 1], &p
, 0);
182 else if (strcmp(atts
[i
], "start") == 0)
183 *offset
= strtoul(atts
[i
+ 1], &p
, 0);
189 get_register_offset(const char **atts
, uint32_t *offset
)
194 for (i
= 0; atts
[i
]; i
+= 2) {
195 if (strcmp(atts
[i
], "num") == 0)
196 *offset
= strtoul(atts
[i
+ 1], &p
, 0);
202 get_start_end_pos(int *start
, int *end
)
204 /* start value has to be mod with 32 as we need the relative
205 * start position in the first DWord. For the end position, add
206 * the length of the field to the start position to get the
207 * relative postion in the 64 bit address.
209 if (*end
- *start
> 32) {
210 int len
= *end
- *start
;
211 *start
= *start
% 32;
214 *start
= *start
% 32;
221 static inline uint64_t
222 mask(int start
, int end
)
226 v
= ~0ULL >> (63 - end
+ start
);
231 static inline uint64_t
232 field(uint64_t value
, int start
, int end
)
234 get_start_end_pos(&start
, &end
);
235 return (value
& mask(start
, end
)) >> (start
);
238 static inline uint64_t
239 field_address(uint64_t value
, int start
, int end
)
241 /* no need to right shift for address/offset */
242 get_start_end_pos(&start
, &end
);
243 return (value
& mask(start
, end
));
246 static struct gen_type
247 string_to_type(struct parser_context
*ctx
, const char *s
)
252 if (strcmp(s
, "int") == 0)
253 return (struct gen_type
) { .kind
= GEN_TYPE_INT
};
254 else if (strcmp(s
, "uint") == 0)
255 return (struct gen_type
) { .kind
= GEN_TYPE_UINT
};
256 else if (strcmp(s
, "bool") == 0)
257 return (struct gen_type
) { .kind
= GEN_TYPE_BOOL
};
258 else if (strcmp(s
, "float") == 0)
259 return (struct gen_type
) { .kind
= GEN_TYPE_FLOAT
};
260 else if (strcmp(s
, "address") == 0)
261 return (struct gen_type
) { .kind
= GEN_TYPE_ADDRESS
};
262 else if (strcmp(s
, "offset") == 0)
263 return (struct gen_type
) { .kind
= GEN_TYPE_OFFSET
};
264 else if (sscanf(s
, "u%d.%d", &i
, &f
) == 2)
265 return (struct gen_type
) { .kind
= GEN_TYPE_UFIXED
, .i
= i
, .f
= f
};
266 else if (sscanf(s
, "s%d.%d", &i
, &f
) == 2)
267 return (struct gen_type
) { .kind
= GEN_TYPE_SFIXED
, .i
= i
, .f
= f
};
268 else if (g
= gen_spec_find_struct(ctx
->spec
, s
), g
!= NULL
)
269 return (struct gen_type
) { .kind
= GEN_TYPE_STRUCT
, .gen_struct
= g
};
270 else if (strcmp(s
, "mbo") == 0)
271 return (struct gen_type
) { .kind
= GEN_TYPE_MBO
};
273 fail(&ctx
->loc
, "invalid type: %s", s
);
276 static struct gen_field
*
277 create_field(struct parser_context
*ctx
, const char **atts
)
279 struct gen_field
*field
;
283 field
= xzalloc(sizeof(*field
));
285 for (i
= 0; atts
[i
]; i
+= 2) {
286 if (strcmp(atts
[i
], "name") == 0)
287 field
->name
= xstrdup(atts
[i
+ 1]);
288 else if (strcmp(atts
[i
], "start") == 0)
289 field
->start
= ctx
->group
->group_offset
+strtoul(atts
[i
+ 1], &p
, 0);
290 else if (strcmp(atts
[i
], "end") == 0) {
291 field
->end
= ctx
->group
->group_offset
+strtoul(atts
[i
+ 1], &p
, 0);
292 if (ctx
->group
->group_offset
)
293 ctx
->group
->group_offset
= field
->end
+1;
294 } else if (strcmp(atts
[i
], "type") == 0)
295 field
->type
= string_to_type(ctx
, atts
[i
+ 1]);
296 else if (strcmp(atts
[i
], "default") == 0 &&
297 field
->start
>= 16 && field
->end
<= 31) {
298 field
->has_default
= true;
299 field
->default_value
= strtoul(atts
[i
+ 1], &p
, 0);
306 static struct gen_value
*
307 create_value(struct parser_context
*ctx
, const char **atts
)
309 struct gen_value
*value
= xzalloc(sizeof(*value
));
311 for (int i
= 0; atts
[i
]; i
+= 2) {
312 if (strcmp(atts
[i
], "name") == 0)
313 value
->name
= xstrdup(atts
[i
+ 1]);
314 else if (strcmp(atts
[i
], "value") == 0)
315 value
->value
= strtoul(atts
[i
+ 1], NULL
, 0);
322 start_element(void *data
, const char *element_name
, const char **atts
)
324 struct parser_context
*ctx
= data
;
326 const char *name
= NULL
;
327 const char *gen
= NULL
;
329 ctx
->loc
.line_number
= XML_GetCurrentLineNumber(ctx
->parser
);
331 for (i
= 0; atts
[i
]; i
+= 2) {
332 if (strcmp(atts
[i
], "name") == 0)
334 else if (strcmp(atts
[i
], "gen") == 0)
338 if (strcmp(element_name
, "genxml") == 0) {
340 fail(&ctx
->loc
, "no platform name given");
342 fail(&ctx
->loc
, "no gen given");
344 ctx
->platform
= xstrdup(name
);
346 int n
= sscanf(gen
, "%d.%d", &major
, &minor
);
348 fail(&ctx
->loc
, "invalid gen given: %s", gen
);
352 ctx
->spec
->gen
= MAKE_GEN(major
, minor
);
353 } else if (strcmp(element_name
, "instruction") == 0 ||
354 strcmp(element_name
, "struct") == 0) {
355 ctx
->group
= create_group(ctx
, name
, atts
);
356 } else if (strcmp(element_name
, "register") == 0) {
357 ctx
->group
= create_group(ctx
, name
, atts
);
358 get_register_offset(atts
, &ctx
->group
->register_offset
);
359 } else if (strcmp(element_name
, "group") == 0) {
360 get_group_offset_count(ctx
, name
, atts
, &ctx
->group
->group_offset
,
361 &ctx
->group
->group_count
);
362 } else if (strcmp(element_name
, "field") == 0) {
364 ctx
->fields
[ctx
->nfields
++] = create_field(ctx
, atts
);
365 if (ctx
->group
->group_count
)
366 ctx
->group
->group_count
--;
367 } while (ctx
->group
->group_count
> 0);
368 } else if (strcmp(element_name
, "enum") == 0) {
369 } else if (strcmp(element_name
, "value") == 0) {
370 if (ctx
->nfields
> 0) {
371 struct gen_field
*field
= ctx
->fields
[ctx
->nfields
- 1];
372 if (field
->n_allocated_values
<= field
->n_values
) {
373 if (field
->n_allocated_values
== 0) {
374 field
->n_allocated_values
= 2;
376 xzalloc(sizeof(field
->values
[0]) * field
->n_allocated_values
);
378 field
->n_allocated_values
*= 2;
380 realloc(field
->values
,
381 sizeof(field
->values
[0]) * field
->n_allocated_values
);
384 field
->values
[field
->n_values
++] = create_value(ctx
, atts
);
390 end_element(void *data
, const char *name
)
392 struct parser_context
*ctx
= data
;
394 if (strcmp(name
, "instruction") == 0 ||
395 strcmp(name
, "struct") == 0 ||
396 strcmp(name
, "register") == 0) {
397 size_t size
= ctx
->nfields
* sizeof(ctx
->fields
[0]);
398 struct gen_group
*group
= ctx
->group
;
400 group
->fields
= xzalloc(size
);
401 group
->nfields
= ctx
->nfields
;
402 memcpy(group
->fields
, ctx
->fields
, size
);
406 for (int i
= 0; i
< group
->nfields
; i
++) {
407 if (group
->fields
[i
]->start
>= 16 &&
408 group
->fields
[i
]->end
<= 31 &&
409 group
->fields
[i
]->has_default
) {
410 group
->opcode_mask
|=
411 mask(group
->fields
[i
]->start
% 32, group
->fields
[i
]->end
% 32);
413 group
->fields
[i
]->default_value
<< group
->fields
[i
]->start
;
417 struct gen_spec
*spec
= ctx
->spec
;
418 if (strcmp(name
, "instruction") == 0)
419 spec
->commands
[spec
->ncommands
++] = group
;
420 else if (strcmp(name
, "struct") == 0)
421 spec
->structs
[spec
->nstructs
++] = group
;
422 else if (strcmp(name
, "register") == 0)
423 spec
->registers
[spec
->nregisters
++] = group
;
424 } else if (strcmp(name
, "group") == 0) {
425 ctx
->group
->group_offset
= 0;
426 ctx
->group
->group_count
= 0;
431 character_data(void *data
, const XML_Char
*s
, int len
)
436 devinfo_to_gen(const struct gen_device_info
*devinfo
)
438 int value
= 10 * devinfo
->gen
;
440 if (devinfo
->is_baytrail
|| devinfo
->is_haswell
)
446 static const struct {
451 { .gen
= 60, .data
= gen6_xml
, .data_length
= sizeof(gen6_xml
) },
452 { .gen
= 70, .data
= gen7_xml
, .data_length
= sizeof(gen7_xml
) },
453 { .gen
= 75, .data
= gen75_xml
, .data_length
= sizeof(gen75_xml
) },
454 { .gen
= 80, .data
= gen8_xml
, .data_length
= sizeof(gen8_xml
) },
455 { .gen
= 90, .data
= gen9_xml
, .data_length
= sizeof(gen9_xml
) }
458 static const uint8_t *
459 devinfo_to_xml_data(const struct gen_device_info
*devinfo
,
460 uint32_t *data_length
)
462 int i
, gen
= devinfo_to_gen(devinfo
);
464 for (i
= 0; i
< ARRAY_SIZE(gen_data
); i
++) {
465 if (gen_data
[i
].gen
== gen
) {
466 *data_length
= gen_data
[i
].data_length
;
467 return gen_data
[i
].data
;
471 unreachable("Unknown generation");
476 gen_spec_load(const struct gen_device_info
*devinfo
)
478 struct parser_context ctx
;
481 uint32_t data_length
= 0;
483 memset(&ctx
, 0, sizeof ctx
);
484 ctx
.parser
= XML_ParserCreate(NULL
);
485 XML_SetUserData(ctx
.parser
, &ctx
);
486 if (ctx
.parser
== NULL
) {
487 fprintf(stderr
, "failed to create parser\n");
491 XML_SetElementHandler(ctx
.parser
, start_element
, end_element
);
492 XML_SetCharacterDataHandler(ctx
.parser
, character_data
);
494 ctx
.spec
= xzalloc(sizeof(*ctx
.spec
));
496 data
= devinfo_to_xml_data(devinfo
, &data_length
);
497 buf
= XML_GetBuffer(ctx
.parser
, data_length
);
499 memcpy(buf
, data
, data_length
);
501 if (XML_ParseBuffer(ctx
.parser
, data_length
, true) == 0) {
503 "Error parsing XML at line %ld col %ld: %s\n",
504 XML_GetCurrentLineNumber(ctx
.parser
),
505 XML_GetCurrentColumnNumber(ctx
.parser
),
506 XML_ErrorString(XML_GetErrorCode(ctx
.parser
)));
507 XML_ParserFree(ctx
.parser
);
511 XML_ParserFree(ctx
.parser
);
517 gen_spec_load_from_path(const struct gen_device_info
*devinfo
,
520 struct parser_context ctx
;
521 size_t len
, filename_len
= strlen(path
) + 20;
522 char *filename
= malloc(filename_len
);
526 len
= snprintf(filename
, filename_len
, "%s/gen%i.xml",
527 path
, devinfo_to_gen(devinfo
));
528 assert(len
< filename_len
);
530 input
= fopen(filename
, "r");
532 fprintf(stderr
, "failed to open xml description\n");
537 memset(&ctx
, 0, sizeof ctx
);
538 ctx
.parser
= XML_ParserCreate(NULL
);
539 XML_SetUserData(ctx
.parser
, &ctx
);
540 if (ctx
.parser
== NULL
) {
541 fprintf(stderr
, "failed to create parser\n");
546 XML_SetElementHandler(ctx
.parser
, start_element
, end_element
);
547 XML_SetCharacterDataHandler(ctx
.parser
, character_data
);
548 ctx
.loc
.filename
= filename
;
549 ctx
.spec
= xzalloc(sizeof(*ctx
.spec
));
552 buf
= XML_GetBuffer(ctx
.parser
, XML_BUFFER_SIZE
);
553 len
= fread(buf
, 1, XML_BUFFER_SIZE
, input
);
555 fprintf(stderr
, "fread: %m\n");
560 if (XML_ParseBuffer(ctx
.parser
, len
, len
== 0) == 0) {
562 "Error parsing XML at line %ld col %ld: %s\n",
563 XML_GetCurrentLineNumber(ctx
.parser
),
564 XML_GetCurrentColumnNumber(ctx
.parser
),
565 XML_ErrorString(XML_GetErrorCode(ctx
.parser
)));
572 XML_ParserFree(ctx
.parser
);
581 gen_spec_find_instruction(struct gen_spec
*spec
, const uint32_t *p
)
583 for (int i
= 0; i
< spec
->ncommands
; i
++) {
584 uint32_t opcode
= *p
& spec
->commands
[i
]->opcode_mask
;
585 if (opcode
== spec
->commands
[i
]->opcode
)
586 return spec
->commands
[i
];
593 gen_group_get_length(struct gen_group
*group
, const uint32_t *p
)
596 uint32_t type
= field(h
, 29, 31);
600 uint32_t opcode
= field(h
, 23, 28);
604 return field(h
, 0, 7) + 2;
608 case 3: /* Render */ {
609 uint32_t subtype
= field(h
, 27, 28);
612 return field(h
, 0, 7) + 2;
618 return field(h
, 0, 7) + 2;
623 unreachable("bad opcode");
627 gen_field_iterator_init(struct gen_field_iterator
*iter
,
628 struct gen_group
*group
,
635 iter
->print_colors
= print_colors
;
639 gen_field_write_value(char *str
, size_t max_length
,
640 struct gen_field
*field
,
643 for (int i
= 0; i
< field
->n_values
; i
++) {
644 if (field
->values
[i
]->value
== value
) {
645 strncpy(str
, field
->values
[i
]->name
, max_length
);
652 gen_field_iterator_next(struct gen_field_iterator
*iter
)
660 if (iter
->i
== iter
->group
->nfields
)
663 f
= iter
->group
->fields
[iter
->i
++];
664 iter
->name
= f
->name
;
665 int index
= f
->start
/ 32;
667 if ((f
->end
- f
->start
) > 32)
668 v
.qw
= ((uint64_t) iter
->p
[index
+1] << 32) | iter
->p
[index
];
670 v
.qw
= iter
->p
[index
];
672 iter
->description
[0] = '\0';
674 switch (f
->type
.kind
) {
675 case GEN_TYPE_UNKNOWN
:
677 uint64_t value
= field(v
.qw
, f
->start
, f
->end
);
678 snprintf(iter
->value
, sizeof(iter
->value
),
680 gen_field_write_value(iter
->description
, sizeof(iter
->description
),
684 case GEN_TYPE_UINT
: {
685 uint64_t value
= field(v
.qw
, f
->start
, f
->end
);
686 snprintf(iter
->value
, sizeof(iter
->value
),
688 gen_field_write_value(iter
->description
, sizeof(iter
->description
),
692 case GEN_TYPE_BOOL
: {
693 const char *true_string
=
694 iter
->print_colors
? "\e[0;35mtrue\e[0m" : "true";
695 snprintf(iter
->value
, sizeof(iter
->value
),
696 "%s", field(v
.qw
, f
->start
, f
->end
) ? true_string
: "false");
700 snprintf(iter
->value
, sizeof(iter
->value
), "%f", v
.f
);
702 case GEN_TYPE_ADDRESS
:
703 case GEN_TYPE_OFFSET
:
704 snprintf(iter
->value
, sizeof(iter
->value
),
705 "0x%08"PRIx64
, field_address(v
.qw
, f
->start
, f
->end
));
707 case GEN_TYPE_STRUCT
:
708 snprintf(iter
->value
, sizeof(iter
->value
),
709 "<struct %s %d>", f
->type
.gen_struct
->name
, (f
->start
/ 32));
711 case GEN_TYPE_UFIXED
:
712 snprintf(iter
->value
, sizeof(iter
->value
),
713 "%f", (float) field(v
.qw
, f
->start
, f
->end
) / (1 << f
->type
.f
));
715 case GEN_TYPE_SFIXED
:
716 /* FIXME: Sign extend extracted field. */
717 snprintf(iter
->value
, sizeof(iter
->value
), "%s", "foo");