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
31 #include <util/macros.h>
35 #define XML_BUFFER_SIZE 4096
37 #define MAKE_GEN(major, minor) ( ((major) << 8) | (minor) )
43 struct gen_group
*commands
[256];
45 struct gen_group
*structs
[256];
47 struct gen_group
*registers
[256];
55 struct parser_context
{
61 struct gen_group
*group
;
64 struct gen_field
*fields
[128];
66 struct gen_spec
*spec
;
70 gen_group_get_name(struct gen_group
*group
)
76 gen_group_get_opcode(struct gen_group
*group
)
82 gen_spec_find_struct(struct gen_spec
*spec
, const char *name
)
84 for (int i
= 0; i
< spec
->nstructs
; i
++)
85 if (strcmp(spec
->structs
[i
]->name
, name
) == 0)
86 return spec
->structs
[i
];
92 gen_spec_get_gen(struct gen_spec
*spec
)
97 static void __attribute__((noreturn
))
98 fail(struct location
*loc
, const char *msg
, ...)
103 fprintf(stderr
, "%s:%d: error: ",
104 loc
->filename
, loc
->line_number
);
105 vfprintf(stderr
, msg
, ap
);
106 fprintf(stderr
, "\n");
112 fail_on_null(void *p
)
115 fprintf(stderr
, "aubinator: out of memory\n");
123 xstrdup(const char *s
)
125 return fail_on_null(strdup(s
));
137 return fail_on_null(zalloc(s
));
140 static struct gen_group
*
141 create_group(struct parser_context
*ctx
, const char *name
, const char **atts
)
143 struct gen_group
*group
;
145 group
= xzalloc(sizeof(*group
));
147 group
->name
= xstrdup(name
);
149 group
->group_offset
= 0;
150 group
->group_count
= 0;
156 get_group_offset_count(struct parser_context
*ctx
, const char *name
,
157 const char **atts
, uint32_t *offset
, uint32_t *count
)
162 for (i
= 0; atts
[i
]; i
+= 2) {
163 if (strcmp(atts
[i
], "count") == 0)
164 *count
= strtoul(atts
[i
+ 1], &p
, 0);
165 else if (strcmp(atts
[i
], "start") == 0)
166 *offset
= strtoul(atts
[i
+ 1], &p
, 0);
171 static inline uint64_t
172 mask(int start
, int end
)
176 v
= ~0ULL >> (63 - end
+ start
);
181 static inline uint64_t
182 field(uint64_t value
, int start
, int end
)
184 /* The field values are obtained from the DWord,
185 * Hence, get the relative start and end positions
186 * by doing a %32 on the start and end positions
188 return (value
& mask(start
% 32, end
% 32)) >> (start
% 32);
191 static inline uint64_t
192 field_address(uint64_t value
, int start
, int end
)
194 /* no need to right shift for address/offset */
195 return (value
& mask(start
% 32, end
% 32));
198 static struct gen_type
199 string_to_type(struct parser_context
*ctx
, const char *s
)
204 if (strcmp(s
, "int") == 0)
205 return (struct gen_type
) { .kind
= GEN_TYPE_INT
};
206 else if (strcmp(s
, "uint") == 0)
207 return (struct gen_type
) { .kind
= GEN_TYPE_UINT
};
208 else if (strcmp(s
, "bool") == 0)
209 return (struct gen_type
) { .kind
= GEN_TYPE_BOOL
};
210 else if (strcmp(s
, "float") == 0)
211 return (struct gen_type
) { .kind
= GEN_TYPE_FLOAT
};
212 else if (strcmp(s
, "address") == 0)
213 return (struct gen_type
) { .kind
= GEN_TYPE_ADDRESS
};
214 else if (strcmp(s
, "offset") == 0)
215 return (struct gen_type
) { .kind
= GEN_TYPE_OFFSET
};
216 else if (sscanf(s
, "u%d.%d", &i
, &f
) == 2)
217 return (struct gen_type
) { .kind
= GEN_TYPE_UFIXED
, .i
= i
, .f
= f
};
218 else if (sscanf(s
, "s%d.%d", &i
, &f
) == 2)
219 return (struct gen_type
) { .kind
= GEN_TYPE_SFIXED
, .i
= i
, .f
= f
};
220 else if (g
= gen_spec_find_struct(ctx
->spec
, s
), g
!= NULL
)
221 return (struct gen_type
) { .kind
= GEN_TYPE_STRUCT
, .gen_struct
= g
};
222 else if (strcmp(s
, "mbo") == 0)
223 return (struct gen_type
) { .kind
= GEN_TYPE_MBO
};
225 fail(&ctx
->loc
, "invalid type: %s", s
);
228 static struct gen_field
*
229 create_field(struct parser_context
*ctx
, const char **atts
)
231 struct gen_field
*field
;
235 field
= xzalloc(sizeof(*field
));
237 for (i
= 0; atts
[i
]; i
+= 2) {
238 if (strcmp(atts
[i
], "name") == 0)
239 field
->name
= xstrdup(atts
[i
+ 1]);
240 else if (strcmp(atts
[i
], "start") == 0)
241 field
->start
= ctx
->group
->group_offset
+strtoul(atts
[i
+ 1], &p
, 0);
242 else if (strcmp(atts
[i
], "end") == 0) {
243 field
->end
= ctx
->group
->group_offset
+strtoul(atts
[i
+ 1], &p
, 0);
244 if (ctx
->group
->group_offset
)
245 ctx
->group
->group_offset
= field
->end
+1;
246 } else if (strcmp(atts
[i
], "type") == 0)
247 field
->type
= string_to_type(ctx
, atts
[i
+ 1]);
248 else if (strcmp(atts
[i
], "default") == 0 &&
249 field
->start
>= 16 && field
->end
<= 31) {
250 field
->has_default
= true;
251 field
->default_value
= strtoul(atts
[i
+ 1], &p
, 0);
259 start_element(void *data
, const char *element_name
, const char **atts
)
261 struct parser_context
*ctx
= data
;
263 const char *name
= NULL
;
264 const char *gen
= NULL
;
266 ctx
->loc
.line_number
= XML_GetCurrentLineNumber(ctx
->parser
);
268 for (i
= 0; atts
[i
]; i
+= 2) {
269 if (strcmp(atts
[i
], "name") == 0)
271 else if (strcmp(atts
[i
], "gen") == 0)
275 if (strcmp(element_name
, "genxml") == 0) {
277 fail(&ctx
->loc
, "no platform name given");
279 fail(&ctx
->loc
, "no gen given");
281 ctx
->platform
= xstrdup(name
);
283 int n
= sscanf(gen
, "%d.%d", &major
, &minor
);
285 fail(&ctx
->loc
, "invalid gen given: %s", gen
);
289 ctx
->spec
->gen
= MAKE_GEN(major
, minor
);
290 } else if (strcmp(element_name
, "instruction") == 0 ||
291 strcmp(element_name
, "struct") == 0 ||
292 strcmp(element_name
, "register") == 0) {
293 ctx
->group
= create_group(ctx
, name
, atts
);
294 } else if (strcmp(element_name
, "group") == 0) {
295 get_group_offset_count(ctx
, name
, atts
, &ctx
->group
->group_offset
,
296 &ctx
->group
->group_count
);
297 } else if (strcmp(element_name
, "field") == 0) {
299 ctx
->fields
[ctx
->nfields
++] = create_field(ctx
, atts
);
300 if (ctx
->group
->group_count
)
301 ctx
->group
->group_count
--;
302 } while (ctx
->group
->group_count
> 0);
303 } else if (strcmp(element_name
, "enum") == 0) {
304 } else if (strcmp(element_name
, "value") == 0) {
309 end_element(void *data
, const char *name
)
311 struct parser_context
*ctx
= data
;
313 if (strcmp(name
, "instruction") == 0 ||
314 strcmp(name
, "struct") == 0 ||
315 strcmp(name
, "register") == 0) {
316 size_t size
= ctx
->nfields
* sizeof(ctx
->fields
[0]);
317 struct gen_group
*group
= ctx
->group
;
319 group
->fields
= xzalloc(size
);
320 group
->nfields
= ctx
->nfields
;
321 memcpy(group
->fields
, ctx
->fields
, size
);
325 for (int i
= 0; i
< group
->nfields
; i
++) {
326 if (group
->fields
[i
]->start
>= 16 &&
327 group
->fields
[i
]->end
<= 31 &&
328 group
->fields
[i
]->has_default
) {
329 group
->opcode_mask
|=
330 mask(group
->fields
[i
]->start
% 32, group
->fields
[i
]->end
% 32);
332 group
->fields
[i
]->default_value
<< group
->fields
[i
]->start
;
336 struct gen_spec
*spec
= ctx
->spec
;
337 if (strcmp(name
, "instruction") == 0)
338 spec
->commands
[spec
->ncommands
++] = group
;
339 else if (strcmp(name
, "struct") == 0)
340 spec
->structs
[spec
->nstructs
++] = group
;
341 else if (strcmp(name
, "register") == 0)
342 spec
->registers
[spec
->nregisters
++] = group
;
343 } else if (strcmp(name
, "group") == 0) {
344 ctx
->group
->group_offset
= 0;
345 ctx
->group
->group_count
= 0;
350 character_data(void *data
, const XML_Char
*s
, int len
)
355 gen_spec_load(const char *filename
)
357 struct parser_context ctx
;
362 input
= fopen(filename
, "r");
363 printf("xml filename = %s\n", filename
);
365 fprintf(stderr
, "failed to open xml description\n");
369 memset(&ctx
, 0, sizeof ctx
);
370 ctx
.parser
= XML_ParserCreate(NULL
);
371 XML_SetUserData(ctx
.parser
, &ctx
);
372 if (ctx
.parser
== NULL
) {
373 fprintf(stderr
, "failed to create parser\n");
378 XML_SetElementHandler(ctx
.parser
, start_element
, end_element
);
379 XML_SetCharacterDataHandler(ctx
.parser
, character_data
);
380 ctx
.loc
.filename
= filename
;
382 ctx
.spec
= xzalloc(sizeof(*ctx
.spec
));
385 buf
= XML_GetBuffer(ctx
.parser
, XML_BUFFER_SIZE
);
386 len
= fread(buf
, 1, XML_BUFFER_SIZE
, input
);
388 fprintf(stderr
, "fread: %m\n");
392 if (XML_ParseBuffer(ctx
.parser
, len
, len
== 0) == 0) {
394 "Error parsing XML at line %ld col %ld: %s\n",
395 XML_GetCurrentLineNumber(ctx
.parser
),
396 XML_GetCurrentColumnNumber(ctx
.parser
),
397 XML_ErrorString(XML_GetErrorCode(ctx
.parser
)));
403 XML_ParserFree(ctx
.parser
);
410 gen_spec_find_instruction(struct gen_spec
*spec
, const uint32_t *p
)
412 for (int i
= 0; i
< spec
->ncommands
; i
++) {
413 uint32_t opcode
= *p
& spec
->commands
[i
]->opcode_mask
;
414 if (opcode
== spec
->commands
[i
]->opcode
)
415 return spec
->commands
[i
];
422 gen_group_get_length(struct gen_group
*group
, const uint32_t *p
)
425 uint32_t type
= field(h
, 29, 31);
429 uint32_t opcode
= field(h
, 23, 28);
433 return field(h
, 0, 7) + 2;
437 case 3: /* Render */ {
438 uint32_t subtype
= field(h
, 27, 28);
441 return field(h
, 0, 7) + 2;
447 return field(h
, 0, 7) + 2;
452 unreachable("bad opcode");
456 gen_field_iterator_init(struct gen_field_iterator
*iter
,
457 struct gen_group
*group
, const uint32_t *p
)
465 gen_field_iterator_next(struct gen_field_iterator
*iter
)
473 if (iter
->i
== iter
->group
->nfields
)
476 f
= iter
->group
->fields
[iter
->i
++];
477 iter
->name
= f
->name
;
478 v
.dw
= iter
->p
[f
->start
/ 32];
479 switch (f
->type
.kind
) {
480 case GEN_TYPE_UNKNOWN
:
482 snprintf(iter
->value
, sizeof(iter
->value
),
483 "%ld", field(v
.dw
, f
->start
, f
->end
));
486 snprintf(iter
->value
, sizeof(iter
->value
),
487 "%lu", field(v
.dw
, f
->start
, f
->end
));
490 snprintf(iter
->value
, sizeof(iter
->value
),
491 "%s", field(v
.dw
, f
->start
, f
->end
) ? "true" : "false");
494 snprintf(iter
->value
, sizeof(iter
->value
), "%f", v
.f
);
496 case GEN_TYPE_ADDRESS
:
497 case GEN_TYPE_OFFSET
:
498 snprintf(iter
->value
, sizeof(iter
->value
),
499 "0x%08lx", field_address(v
.dw
, f
->start
, f
->end
));
501 case GEN_TYPE_STRUCT
:
502 snprintf(iter
->value
, sizeof(iter
->value
),
503 "<struct %s %d>", f
->type
.gen_struct
->name
, (f
->start
/ 32));
505 case GEN_TYPE_UFIXED
:
506 snprintf(iter
->value
, sizeof(iter
->value
),
507 "%f", (float) field(v
.dw
, f
->start
, f
->end
) / (1 << f
->type
.f
));
509 case GEN_TYPE_SFIXED
:
510 /* FIXME: Sign extend extracted field. */
511 snprintf(iter
->value
, sizeof(iter
->value
), "%s", "foo");