1 /*
2 * Copyright © 2018 Intel Corporation
3 *
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:
10 *
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
13 * Software.
14 *
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 FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *
23 */
24
25 #include <stdio.h>
26 #include <getopt.h>
27 #include "i965_asm.h"
28
29 enum opt_output_type {
30 OPT_OUTPUT_HEX,
31 OPT_OUTPUT_C_LITERAL,
32 OPT_OUTPUT_BIN,
33 };
34
35 extern FILE *yyin;
36 struct brw_codegen *p;
37 static enum opt_output_type output_type = OPT_OUTPUT_BIN;
38 char *input_filename = NULL;
39 int errors;
40
41 struct list_head instr_labels;
42 struct list_head target_labels;
43
44 static void
print_help(const char * progname,FILE * file)45 print_help(const char *progname, FILE *file)
46 {
47 fprintf(file,
48 "Usage: %s [OPTION] inputfile\n"
49 "Assemble i965 instructions from input file.\n\n"
50 " -h, --help display this help and exit\n"
51 " -t, --type=OUTPUT_TYPE OUTPUT_TYPE can be 'bin' (default if omitted),\n"
52 " 'c_literal', or 'hex'\n"
53 " -o, --output specify output file\n"
54 " --compact print compacted instructions\n"
55 " -g, --gen=platform assemble instructions for given \n"
56 " platform (3 letter platform name)\n"
57 "Example:\n"
58 " i965_asm -g kbl input.asm -t hex -o output\n",
59 progname);
60 }
61
62 static uint32_t
get_dword(const brw_inst * inst,int idx)63 get_dword(const brw_inst *inst, int idx)
64 {
65 uint32_t dword;
66 memcpy(&dword, (char *)inst + 4 * idx, sizeof(dword));
67 return dword;
68 }
69
70 static void
print_instruction(FILE * output,bool compact,const brw_inst * instruction)71 print_instruction(FILE *output, bool compact, const brw_inst *instruction)
72 {
73 int byte_limit;
74
75 byte_limit = (compact == true) ? 8 : 16;
76
77 switch (output_type) {
78 case OPT_OUTPUT_HEX: {
79 fprintf(output, "%02x", ((unsigned char *)instruction)[0]);
80
81 for (unsigned i = 1; i < byte_limit; i++) {
82 fprintf(output, " %02x", ((unsigned char *)instruction)[i]);
83 }
84 break;
85 }
86 case OPT_OUTPUT_C_LITERAL: {
87 fprintf(output, "\t0x%08x,", get_dword(instruction, 0));
88
89 for (unsigned i = 1; i < byte_limit / 4; i++)
90 fprintf(output, " 0x%08x,", get_dword(instruction, i));
91
92 break;
93 }
94 case OPT_OUTPUT_BIN:
95 fwrite(instruction, 1, byte_limit, output);
96 break;
97 }
98
99 if (output_type != OPT_OUTPUT_BIN) {
100 fprintf(output, "\n");
101 }
102 }
103
104 static struct gen_device_info *
i965_disasm_init(uint16_t pci_id)105 i965_disasm_init(uint16_t pci_id)
106 {
107 struct gen_device_info *devinfo;
108
109 devinfo = malloc(sizeof *devinfo);
110 if (devinfo == NULL)
111 return NULL;
112
113 if (!gen_get_device_info_from_pci_id(pci_id, devinfo)) {
114 fprintf(stderr, "can't find device information: pci_id=0x%x\n",
115 pci_id);
116 free(devinfo);
117 return NULL;
118 }
119
120 return devinfo;
121 }
122
123 static bool
i965_postprocess_labels()124 i965_postprocess_labels()
125 {
126 if (p->devinfo->gen < 6) {
127 return true;
128 }
129
130 void *store = p->store;
131
132 struct target_label *tlabel;
133 struct instr_label *ilabel, *s;
134
135 const unsigned to_bytes_scale = brw_jump_scale(p->devinfo);
136
137 LIST_FOR_EACH_ENTRY(tlabel, &target_labels, link) {
138 LIST_FOR_EACH_ENTRY_SAFE(ilabel, s, &instr_labels, link) {
139 if (!strcmp(tlabel->name, ilabel->name)) {
140 brw_inst *inst = store + ilabel->offset;
141
142 int relative_offset = (tlabel->offset - ilabel->offset) / sizeof(brw_inst);
143 relative_offset *= to_bytes_scale;
144
145 unsigned opcode = brw_inst_opcode(p->devinfo, inst);
146
147 if (ilabel->type == INSTR_LABEL_JIP) {
148 switch (opcode) {
149 case BRW_OPCODE_IF:
150 case BRW_OPCODE_ELSE:
151 case BRW_OPCODE_ENDIF:
152 case BRW_OPCODE_WHILE:
153 if (p->devinfo->gen >= 7) {
154 brw_inst_set_jip(p->devinfo, inst, relative_offset);
155 } else if (p->devinfo->gen == 6) {
156 brw_inst_set_gen6_jump_count(p->devinfo, inst, relative_offset);
157 }
158 break;
159 case BRW_OPCODE_BREAK:
160 case BRW_OPCODE_HALT:
161 case BRW_OPCODE_CONTINUE:
162 brw_inst_set_jip(p->devinfo, inst, relative_offset);
163 break;
164 default:
165 fprintf(stderr, "Unknown opcode %d with JIP label\n", opcode);
166 return false;
167 }
168 } else {
169 switch (opcode) {
170 case BRW_OPCODE_IF:
171 case BRW_OPCODE_ELSE:
172 if (p->devinfo->gen > 7) {
173 brw_inst_set_uip(p->devinfo, inst, relative_offset);
174 } else if (p->devinfo->gen == 7) {
175 brw_inst_set_uip(p->devinfo, inst, relative_offset);
176 } else if (p->devinfo->gen == 6) {
177 // Nothing
178 }
179 break;
180 case BRW_OPCODE_WHILE:
181 case BRW_OPCODE_ENDIF:
182 fprintf(stderr, "WHILE/ENDIF cannot have UIP offset\n");
183 return false;
184 case BRW_OPCODE_BREAK:
185 case BRW_OPCODE_CONTINUE:
186 case BRW_OPCODE_HALT:
187 brw_inst_set_uip(p->devinfo, inst, relative_offset);
188 break;
189 default:
190 fprintf(stderr, "Unknown opcode %d with UIP label\n", opcode);
191 return false;
192 }
193 }
194
195 list_del(&ilabel->link);
196 }
197 }
198 }
199
200 LIST_FOR_EACH_ENTRY(ilabel, &instr_labels, link) {
201 fprintf(stderr, "Unknown label '%s'\n", ilabel->name);
202 }
203
204 return list_is_empty(&instr_labels);
205 }
206
main(int argc,char ** argv)207 int main(int argc, char **argv)
208 {
209 char *output_file = NULL;
210 char c;
211 FILE *output = stdout;
212 bool help = false, compact = false;
213 void *store;
214 uint64_t pci_id = 0;
215 int offset = 0, err;
216 int start_offset = 0;
217 struct disasm_info *disasm_info;
218 struct gen_device_info *devinfo = NULL;
219 int result = EXIT_FAILURE;
220 list_inithead(&instr_labels);
221 list_inithead(&target_labels);
222
223 const struct option i965_asm_opts[] = {
224 { "help", no_argument, (int *) &help, true },
225 { "type", required_argument, NULL, 't' },
226 { "gen", required_argument, NULL, 'g' },
227 { "output", required_argument, NULL, 'o' },
228 { "compact", no_argument, (int *) &compact, true },
229 { NULL, 0, NULL, 0 }
230 };
231
232 while ((c = getopt_long(argc, argv, ":t:g:o:h", i965_asm_opts, NULL)) != -1) {
233 switch (c) {
234 case 'g': {
235 const int id = gen_device_name_to_pci_device_id(optarg);
236 if (id < 0) {
237 fprintf(stderr, "can't parse gen: '%s', expected 3 letter "
238 "platform name\n", optarg);
239 goto end;
240 } else {
241 pci_id = id;
242 }
243 break;
244 }
245 case 'h':
246 help = true;
247 print_help(argv[0], stderr);
248 goto end;
249 case 't': {
250 if (strcmp(optarg, "hex") == 0) {
251 output_type = OPT_OUTPUT_HEX;
252 } else if (strcmp(optarg, "c_literal") == 0) {
253 output_type = OPT_OUTPUT_C_LITERAL;
254 } else if (strcmp(optarg, "bin") == 0) {
255 output_type = OPT_OUTPUT_BIN;
256 } else {
257 fprintf(stderr, "invalid value for --type: %s\n", optarg);
258 goto end;
259 }
260 break;
261 }
262 case 'o':
263 output_file = strdup(optarg);
264 break;
265 case 0:
266 break;
267 case ':':
268 fprintf(stderr, "%s: option `-%c' requires an argument\n",
269 argv[0], optopt);
270 goto end;
271 case '?':
272 default:
273 fprintf(stderr, "%s: option `-%c' is invalid: ignored\n",
274 argv[0], optopt);
275 goto end;
276 }
277 }
278
279 if (help || !pci_id) {
280 print_help(argv[0], stderr);
281 goto end;
282 }
283
284 if (!argv[optind]) {
285 fprintf(stderr, "Please specify input file\n");
286 goto end;
287 }
288
289 input_filename = strdup(argv[optind]);
290 yyin = fopen(input_filename, "r");
291 if (!yyin) {
292 fprintf(stderr, "Unable to read input file : %s\n",
293 input_filename);
294 goto end;
295 }
296
297 if (output_file) {
298 output = fopen(output_file, "w");
299 if (!output) {
300 fprintf(stderr, "Couldn't open output file\n");
301 goto end;
302 }
303 }
304
305 devinfo = i965_disasm_init(pci_id);
306 if (!devinfo) {
307 fprintf(stderr, "Unable to allocate memory for "
308 "gen_device_info struct instance.\n");
309 goto end;
310 }
311
312 p = rzalloc(NULL, struct brw_codegen);
313 brw_init_codegen(devinfo, p, p);
314 p->automatic_exec_sizes = false;
315
316 err = yyparse();
317 if (err || errors)
318 goto end;
319
320 if (!i965_postprocess_labels())
321 goto end;
322
323 store = p->store;
324
325 disasm_info = disasm_initialize(p->devinfo, NULL);
326 if (!disasm_info) {
327 fprintf(stderr, "Unable to initialize disasm_info struct instance\n");
328 goto end;
329 }
330
331 if (output_type == OPT_OUTPUT_C_LITERAL)
332 fprintf(output, "{\n");
333
334 brw_validate_instructions(p->devinfo, p->store, 0,
335 p->next_insn_offset, disasm_info);
336
337 const int nr_insn = (p->next_insn_offset - start_offset) / 16;
338
339 if (compact)
340 brw_compact_instructions(p, start_offset, disasm_info);
341
342 for (int i = 0; i < nr_insn; i++) {
343 const brw_inst *insn = store + offset;
344 bool compacted = false;
345
346 if (compact && brw_inst_cmpt_control(p->devinfo, insn)) {
347 offset += 8;
348 compacted = true;
349 } else {
350 offset += 16;
351 }
352
353 print_instruction(output, compacted, insn);
354 }
355
356 ralloc_free(disasm_info);
357
358 if (output_type == OPT_OUTPUT_C_LITERAL)
359 fprintf(output, "}");
360
361 result = EXIT_SUCCESS;
362 goto end;
363
364 end:
365 free(input_filename);
366 free(output_file);
367
368 if (yyin)
369 fclose(yyin);
370
371 if (output)
372 fclose(output);
373
374 if (p)
375 ralloc_free(p);
376
377 if (devinfo)
378 free(devinfo);
379
380 exit(result);
381 }
382