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 intel_device_info *
i965_disasm_init(uint16_t pci_id)105 i965_disasm_init(uint16_t pci_id)
106 {
107    struct intel_device_info *devinfo;
108 
109    devinfo = malloc(sizeof *devinfo);
110    if (devinfo == NULL)
111       return NULL;
112 
113    if (!intel_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->ver < 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->ver >= 7) {
154                      brw_inst_set_jip(p->devinfo, inst, relative_offset);
155                   } else if (p->devinfo->ver == 6) {
156                      brw_inst_set_gfx6_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->ver > 7) {
173                      brw_inst_set_uip(p->devinfo, inst, relative_offset);
174                   } else if (p->devinfo->ver == 7) {
175                      brw_inst_set_uip(p->devinfo, inst, relative_offset);
176                   } else if (p->devinfo->ver == 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 intel_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 = intel_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                       "intel_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