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 29enum opt_output_type { 30 OPT_OUTPUT_HEX, 31 OPT_OUTPUT_C_LITERAL, 32 OPT_OUTPUT_BIN, 33}; 34 35extern FILE *yyin; 36struct brw_codegen *p; 37static enum opt_output_type output_type = OPT_OUTPUT_BIN; 38char *input_filename = NULL; 39int errors; 40 41struct list_head instr_labels; 42struct list_head target_labels; 43 44static void 45print_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 62static uint32_t 63get_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 70static void 71print_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 104static struct intel_device_info * 105i965_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 123static bool 124i965_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->isa, 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 207int 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 struct brw_isa_info isa; 313 brw_init_isa_info(&isa, devinfo); 314 315 p = rzalloc(NULL, struct brw_codegen); 316 brw_init_codegen(&isa, p, p); 317 p->automatic_exec_sizes = false; 318 319 err = yyparse(); 320 if (err || errors) 321 goto end; 322 323 if (!i965_postprocess_labels()) 324 goto end; 325 326 store = p->store; 327 328 disasm_info = disasm_initialize(p->isa, NULL); 329 if (!disasm_info) { 330 fprintf(stderr, "Unable to initialize disasm_info struct instance\n"); 331 goto end; 332 } 333 334 if (output_type == OPT_OUTPUT_C_LITERAL) 335 fprintf(output, "{\n"); 336 337 brw_validate_instructions(p->isa, p->store, 0, 338 p->next_insn_offset, disasm_info); 339 340 const int nr_insn = (p->next_insn_offset - start_offset) / 16; 341 342 if (compact) 343 brw_compact_instructions(p, start_offset, disasm_info); 344 345 for (int i = 0; i < nr_insn; i++) { 346 const brw_inst *insn = store + offset; 347 bool compacted = false; 348 349 if (compact && brw_inst_cmpt_control(p->devinfo, insn)) { 350 offset += 8; 351 compacted = true; 352 } else { 353 offset += 16; 354 } 355 356 print_instruction(output, compacted, insn); 357 } 358 359 ralloc_free(disasm_info); 360 361 if (output_type == OPT_OUTPUT_C_LITERAL) 362 fprintf(output, "}"); 363 364 result = EXIT_SUCCESS; 365 goto end; 366 367end: 368 free(input_filename); 369 free(output_file); 370 371 if (yyin) 372 fclose(yyin); 373 374 if (output) 375 fclose(output); 376 377 if (p) 378 ralloc_free(p); 379 380 if (devinfo) 381 free(devinfo); 382 383 exit(result); 384} 385