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