17ec681f3Smrg/*
27ec681f3Smrg * Copyright © 2018 Intel Corporation
37ec681f3Smrg *
47ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
57ec681f3Smrg * copy of this software and associated documentation files (the "Software"),
67ec681f3Smrg * to deal in the Software without restriction, including without limitation
77ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
87ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the
97ec681f3Smrg * Software is furnished to do so, subject to the following conditions:
107ec681f3Smrg *
117ec681f3Smrg * The above copyright notice and this permission notice (including the next
127ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the
137ec681f3Smrg * Software.
147ec681f3Smrg *
157ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
167ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
177ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
187ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
197ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
207ec681f3Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
217ec681f3Smrg * SOFTWARE.
227ec681f3Smrg *
237ec681f3Smrg */
247ec681f3Smrg
257ec681f3Smrg#include <stdio.h>
267ec681f3Smrg#include <getopt.h>
277ec681f3Smrg#include "i965_asm.h"
287ec681f3Smrg
297ec681f3Smrgenum opt_output_type {
307ec681f3Smrg   OPT_OUTPUT_HEX,
317ec681f3Smrg   OPT_OUTPUT_C_LITERAL,
327ec681f3Smrg   OPT_OUTPUT_BIN,
337ec681f3Smrg};
347ec681f3Smrg
357ec681f3Smrgextern FILE *yyin;
367ec681f3Smrgstruct brw_codegen *p;
377ec681f3Smrgstatic enum opt_output_type output_type = OPT_OUTPUT_BIN;
387ec681f3Smrgchar *input_filename = NULL;
397ec681f3Smrgint errors;
407ec681f3Smrg
417ec681f3Smrgstruct list_head instr_labels;
427ec681f3Smrgstruct list_head target_labels;
437ec681f3Smrg
447ec681f3Smrgstatic void
457ec681f3Smrgprint_help(const char *progname, FILE *file)
467ec681f3Smrg{
477ec681f3Smrg   fprintf(file,
487ec681f3Smrg           "Usage: %s [OPTION] inputfile\n"
497ec681f3Smrg           "Assemble i965 instructions from input file.\n\n"
507ec681f3Smrg           "    -h, --help             display this help and exit\n"
517ec681f3Smrg           "    -t, --type=OUTPUT_TYPE OUTPUT_TYPE can be 'bin' (default if omitted),\n"
527ec681f3Smrg           "                           'c_literal', or 'hex'\n"
537ec681f3Smrg           "    -o, --output           specify output file\n"
547ec681f3Smrg           "        --compact          print compacted instructions\n"
557ec681f3Smrg           "    -g, --gen=platform     assemble instructions for given \n"
567ec681f3Smrg           "                           platform (3 letter platform name)\n"
577ec681f3Smrg           "Example:\n"
587ec681f3Smrg           "    i965_asm -g kbl input.asm -t hex -o output\n",
597ec681f3Smrg           progname);
607ec681f3Smrg}
617ec681f3Smrg
627ec681f3Smrgstatic uint32_t
637ec681f3Smrgget_dword(const brw_inst *inst, int idx)
647ec681f3Smrg{
657ec681f3Smrg   uint32_t dword;
667ec681f3Smrg   memcpy(&dword, (char *)inst + 4 * idx, sizeof(dword));
677ec681f3Smrg   return dword;
687ec681f3Smrg}
697ec681f3Smrg
707ec681f3Smrgstatic void
717ec681f3Smrgprint_instruction(FILE *output, bool compact, const brw_inst *instruction)
727ec681f3Smrg{
737ec681f3Smrg   int byte_limit;
747ec681f3Smrg
757ec681f3Smrg   byte_limit = (compact == true) ? 8 : 16;
767ec681f3Smrg
777ec681f3Smrg   switch (output_type) {
787ec681f3Smrg   case OPT_OUTPUT_HEX: {
797ec681f3Smrg      fprintf(output, "%02x", ((unsigned char *)instruction)[0]);
807ec681f3Smrg
817ec681f3Smrg      for (unsigned i = 1; i < byte_limit; i++) {
827ec681f3Smrg         fprintf(output, " %02x", ((unsigned char *)instruction)[i]);
837ec681f3Smrg      }
847ec681f3Smrg      break;
857ec681f3Smrg   }
867ec681f3Smrg   case OPT_OUTPUT_C_LITERAL: {
877ec681f3Smrg      fprintf(output, "\t0x%08x,", get_dword(instruction, 0));
887ec681f3Smrg
897ec681f3Smrg      for (unsigned i = 1; i < byte_limit / 4; i++)
907ec681f3Smrg         fprintf(output, " 0x%08x,", get_dword(instruction, i));
917ec681f3Smrg
927ec681f3Smrg      break;
937ec681f3Smrg   }
947ec681f3Smrg   case OPT_OUTPUT_BIN:
957ec681f3Smrg      fwrite(instruction, 1, byte_limit, output);
967ec681f3Smrg      break;
977ec681f3Smrg   }
987ec681f3Smrg
997ec681f3Smrg   if (output_type != OPT_OUTPUT_BIN) {
1007ec681f3Smrg      fprintf(output, "\n");
1017ec681f3Smrg   }
1027ec681f3Smrg}
1037ec681f3Smrg
1047ec681f3Smrgstatic struct intel_device_info *
1057ec681f3Smrgi965_disasm_init(uint16_t pci_id)
1067ec681f3Smrg{
1077ec681f3Smrg   struct intel_device_info *devinfo;
1087ec681f3Smrg
1097ec681f3Smrg   devinfo = malloc(sizeof *devinfo);
1107ec681f3Smrg   if (devinfo == NULL)
1117ec681f3Smrg      return NULL;
1127ec681f3Smrg
1137ec681f3Smrg   if (!intel_get_device_info_from_pci_id(pci_id, devinfo)) {
1147ec681f3Smrg      fprintf(stderr, "can't find device information: pci_id=0x%x\n",
1157ec681f3Smrg              pci_id);
1167ec681f3Smrg      free(devinfo);
1177ec681f3Smrg      return NULL;
1187ec681f3Smrg   }
1197ec681f3Smrg
1207ec681f3Smrg   return devinfo;
1217ec681f3Smrg}
1227ec681f3Smrg
1237ec681f3Smrgstatic bool
1247ec681f3Smrgi965_postprocess_labels()
1257ec681f3Smrg{
1267ec681f3Smrg   if (p->devinfo->ver < 6) {
1277ec681f3Smrg      return true;
1287ec681f3Smrg   }
1297ec681f3Smrg
1307ec681f3Smrg   void *store = p->store;
1317ec681f3Smrg
1327ec681f3Smrg   struct target_label *tlabel;
1337ec681f3Smrg   struct instr_label *ilabel, *s;
1347ec681f3Smrg
1357ec681f3Smrg   const unsigned to_bytes_scale = brw_jump_scale(p->devinfo);
1367ec681f3Smrg
1377ec681f3Smrg   LIST_FOR_EACH_ENTRY(tlabel, &target_labels, link) {
1387ec681f3Smrg      LIST_FOR_EACH_ENTRY_SAFE(ilabel, s, &instr_labels, link) {
1397ec681f3Smrg         if (!strcmp(tlabel->name, ilabel->name)) {
1407ec681f3Smrg            brw_inst *inst = store + ilabel->offset;
1417ec681f3Smrg
1427ec681f3Smrg            int relative_offset = (tlabel->offset - ilabel->offset) / sizeof(brw_inst);
1437ec681f3Smrg            relative_offset *= to_bytes_scale;
1447ec681f3Smrg
1457ec681f3Smrg            unsigned opcode = brw_inst_opcode(p->devinfo, inst);
1467ec681f3Smrg
1477ec681f3Smrg            if (ilabel->type == INSTR_LABEL_JIP) {
1487ec681f3Smrg               switch (opcode) {
1497ec681f3Smrg               case BRW_OPCODE_IF:
1507ec681f3Smrg               case BRW_OPCODE_ELSE:
1517ec681f3Smrg               case BRW_OPCODE_ENDIF:
1527ec681f3Smrg               case BRW_OPCODE_WHILE:
1537ec681f3Smrg                  if (p->devinfo->ver >= 7) {
1547ec681f3Smrg                     brw_inst_set_jip(p->devinfo, inst, relative_offset);
1557ec681f3Smrg                  } else if (p->devinfo->ver == 6) {
1567ec681f3Smrg                     brw_inst_set_gfx6_jump_count(p->devinfo, inst, relative_offset);
1577ec681f3Smrg                  }
1587ec681f3Smrg                  break;
1597ec681f3Smrg               case BRW_OPCODE_BREAK:
1607ec681f3Smrg               case BRW_OPCODE_HALT:
1617ec681f3Smrg               case BRW_OPCODE_CONTINUE:
1627ec681f3Smrg                  brw_inst_set_jip(p->devinfo, inst, relative_offset);
1637ec681f3Smrg                  break;
1647ec681f3Smrg               default:
1657ec681f3Smrg                  fprintf(stderr, "Unknown opcode %d with JIP label\n", opcode);
1667ec681f3Smrg                  return false;
1677ec681f3Smrg               }
1687ec681f3Smrg            } else {
1697ec681f3Smrg               switch (opcode) {
1707ec681f3Smrg               case BRW_OPCODE_IF:
1717ec681f3Smrg               case BRW_OPCODE_ELSE:
1727ec681f3Smrg                  if (p->devinfo->ver > 7) {
1737ec681f3Smrg                     brw_inst_set_uip(p->devinfo, inst, relative_offset);
1747ec681f3Smrg                  } else if (p->devinfo->ver == 7) {
1757ec681f3Smrg                     brw_inst_set_uip(p->devinfo, inst, relative_offset);
1767ec681f3Smrg                  } else if (p->devinfo->ver == 6) {
1777ec681f3Smrg                     // Nothing
1787ec681f3Smrg                  }
1797ec681f3Smrg                  break;
1807ec681f3Smrg               case BRW_OPCODE_WHILE:
1817ec681f3Smrg               case BRW_OPCODE_ENDIF:
1827ec681f3Smrg                  fprintf(stderr, "WHILE/ENDIF cannot have UIP offset\n");
1837ec681f3Smrg                  return false;
1847ec681f3Smrg               case BRW_OPCODE_BREAK:
1857ec681f3Smrg               case BRW_OPCODE_CONTINUE:
1867ec681f3Smrg               case BRW_OPCODE_HALT:
1877ec681f3Smrg                  brw_inst_set_uip(p->devinfo, inst, relative_offset);
1887ec681f3Smrg                  break;
1897ec681f3Smrg               default:
1907ec681f3Smrg                  fprintf(stderr, "Unknown opcode %d with UIP label\n", opcode);
1917ec681f3Smrg                  return false;
1927ec681f3Smrg               }
1937ec681f3Smrg            }
1947ec681f3Smrg
1957ec681f3Smrg            list_del(&ilabel->link);
1967ec681f3Smrg         }
1977ec681f3Smrg      }
1987ec681f3Smrg   }
1997ec681f3Smrg
2007ec681f3Smrg   LIST_FOR_EACH_ENTRY(ilabel, &instr_labels, link) {
2017ec681f3Smrg      fprintf(stderr, "Unknown label '%s'\n", ilabel->name);
2027ec681f3Smrg   }
2037ec681f3Smrg
2047ec681f3Smrg   return list_is_empty(&instr_labels);
2057ec681f3Smrg}
2067ec681f3Smrg
2077ec681f3Smrgint main(int argc, char **argv)
2087ec681f3Smrg{
2097ec681f3Smrg   char *output_file = NULL;
2107ec681f3Smrg   char c;
2117ec681f3Smrg   FILE *output = stdout;
2127ec681f3Smrg   bool help = false, compact = false;
2137ec681f3Smrg   void *store;
2147ec681f3Smrg   uint64_t pci_id = 0;
2157ec681f3Smrg   int offset = 0, err;
2167ec681f3Smrg   int start_offset = 0;
2177ec681f3Smrg   struct disasm_info *disasm_info;
2187ec681f3Smrg   struct intel_device_info *devinfo = NULL;
2197ec681f3Smrg   int result = EXIT_FAILURE;
2207ec681f3Smrg   list_inithead(&instr_labels);
2217ec681f3Smrg   list_inithead(&target_labels);
2227ec681f3Smrg
2237ec681f3Smrg   const struct option i965_asm_opts[] = {
2247ec681f3Smrg      { "help",          no_argument,       (int *) &help,      true },
2257ec681f3Smrg      { "type",          required_argument, NULL,               't' },
2267ec681f3Smrg      { "gen",           required_argument, NULL,               'g' },
2277ec681f3Smrg      { "output",        required_argument, NULL,               'o' },
2287ec681f3Smrg      { "compact",       no_argument,       (int *) &compact,   true },
2297ec681f3Smrg      { NULL,            0,                 NULL,               0 }
2307ec681f3Smrg   };
2317ec681f3Smrg
2327ec681f3Smrg   while ((c = getopt_long(argc, argv, ":t:g:o:h", i965_asm_opts, NULL)) != -1) {
2337ec681f3Smrg      switch (c) {
2347ec681f3Smrg      case 'g': {
2357ec681f3Smrg         const int id = intel_device_name_to_pci_device_id(optarg);
2367ec681f3Smrg         if (id < 0) {
2377ec681f3Smrg            fprintf(stderr, "can't parse gen: '%s', expected 3 letter "
2387ec681f3Smrg                            "platform name\n", optarg);
2397ec681f3Smrg            goto end;
2407ec681f3Smrg         } else {
2417ec681f3Smrg            pci_id = id;
2427ec681f3Smrg         }
2437ec681f3Smrg         break;
2447ec681f3Smrg      }
2457ec681f3Smrg      case 'h':
2467ec681f3Smrg         help = true;
2477ec681f3Smrg         print_help(argv[0], stderr);
2487ec681f3Smrg         goto end;
2497ec681f3Smrg      case 't': {
2507ec681f3Smrg         if (strcmp(optarg, "hex") == 0) {
2517ec681f3Smrg            output_type = OPT_OUTPUT_HEX;
2527ec681f3Smrg         } else if (strcmp(optarg, "c_literal") == 0) {
2537ec681f3Smrg            output_type = OPT_OUTPUT_C_LITERAL;
2547ec681f3Smrg         } else if (strcmp(optarg, "bin") == 0) {
2557ec681f3Smrg            output_type = OPT_OUTPUT_BIN;
2567ec681f3Smrg         } else {
2577ec681f3Smrg            fprintf(stderr, "invalid value for --type: %s\n", optarg);
2587ec681f3Smrg            goto end;
2597ec681f3Smrg         }
2607ec681f3Smrg         break;
2617ec681f3Smrg      }
2627ec681f3Smrg      case 'o':
2637ec681f3Smrg         output_file = strdup(optarg);
2647ec681f3Smrg         break;
2657ec681f3Smrg      case 0:
2667ec681f3Smrg         break;
2677ec681f3Smrg      case ':':
2687ec681f3Smrg         fprintf(stderr, "%s: option `-%c' requires an argument\n",
2697ec681f3Smrg                 argv[0], optopt);
2707ec681f3Smrg         goto end;
2717ec681f3Smrg      case '?':
2727ec681f3Smrg      default:
2737ec681f3Smrg         fprintf(stderr, "%s: option `-%c' is invalid: ignored\n",
2747ec681f3Smrg                 argv[0], optopt);
2757ec681f3Smrg         goto end;
2767ec681f3Smrg      }
2777ec681f3Smrg   }
2787ec681f3Smrg
2797ec681f3Smrg   if (help || !pci_id) {
2807ec681f3Smrg      print_help(argv[0], stderr);
2817ec681f3Smrg      goto end;
2827ec681f3Smrg   }
2837ec681f3Smrg
2847ec681f3Smrg   if (!argv[optind]) {
2857ec681f3Smrg      fprintf(stderr, "Please specify input file\n");
2867ec681f3Smrg      goto end;
2877ec681f3Smrg   }
2887ec681f3Smrg
2897ec681f3Smrg   input_filename = strdup(argv[optind]);
2907ec681f3Smrg   yyin = fopen(input_filename, "r");
2917ec681f3Smrg   if (!yyin) {
2927ec681f3Smrg      fprintf(stderr, "Unable to read input file : %s\n",
2937ec681f3Smrg              input_filename);
2947ec681f3Smrg      goto end;
2957ec681f3Smrg   }
2967ec681f3Smrg
2977ec681f3Smrg   if (output_file) {
2987ec681f3Smrg      output = fopen(output_file, "w");
2997ec681f3Smrg      if (!output) {
3007ec681f3Smrg         fprintf(stderr, "Couldn't open output file\n");
3017ec681f3Smrg         goto end;
3027ec681f3Smrg      }
3037ec681f3Smrg   }
3047ec681f3Smrg
3057ec681f3Smrg   devinfo = i965_disasm_init(pci_id);
3067ec681f3Smrg   if (!devinfo) {
3077ec681f3Smrg      fprintf(stderr, "Unable to allocate memory for "
3087ec681f3Smrg                      "intel_device_info struct instance.\n");
3097ec681f3Smrg      goto end;
3107ec681f3Smrg   }
3117ec681f3Smrg
3127ec681f3Smrg   p = rzalloc(NULL, struct brw_codegen);
3137ec681f3Smrg   brw_init_codegen(devinfo, p, p);
3147ec681f3Smrg   p->automatic_exec_sizes = false;
3157ec681f3Smrg
3167ec681f3Smrg   err = yyparse();
3177ec681f3Smrg   if (err || errors)
3187ec681f3Smrg      goto end;
3197ec681f3Smrg
3207ec681f3Smrg   if (!i965_postprocess_labels())
3217ec681f3Smrg      goto end;
3227ec681f3Smrg
3237ec681f3Smrg   store = p->store;
3247ec681f3Smrg
3257ec681f3Smrg   disasm_info = disasm_initialize(p->devinfo, NULL);
3267ec681f3Smrg   if (!disasm_info) {
3277ec681f3Smrg      fprintf(stderr, "Unable to initialize disasm_info struct instance\n");
3287ec681f3Smrg      goto end;
3297ec681f3Smrg   }
3307ec681f3Smrg
3317ec681f3Smrg   if (output_type == OPT_OUTPUT_C_LITERAL)
3327ec681f3Smrg      fprintf(output, "{\n");
3337ec681f3Smrg
3347ec681f3Smrg   brw_validate_instructions(p->devinfo, p->store, 0,
3357ec681f3Smrg                             p->next_insn_offset, disasm_info);
3367ec681f3Smrg
3377ec681f3Smrg   const int nr_insn = (p->next_insn_offset - start_offset) / 16;
3387ec681f3Smrg
3397ec681f3Smrg   if (compact)
3407ec681f3Smrg      brw_compact_instructions(p, start_offset, disasm_info);
3417ec681f3Smrg
3427ec681f3Smrg   for (int i = 0; i < nr_insn; i++) {
3437ec681f3Smrg      const brw_inst *insn = store + offset;
3447ec681f3Smrg      bool compacted = false;
3457ec681f3Smrg
3467ec681f3Smrg      if (compact && brw_inst_cmpt_control(p->devinfo, insn)) {
3477ec681f3Smrg            offset += 8;
3487ec681f3Smrg            compacted = true;
3497ec681f3Smrg      } else {
3507ec681f3Smrg            offset += 16;
3517ec681f3Smrg      }
3527ec681f3Smrg
3537ec681f3Smrg      print_instruction(output, compacted, insn);
3547ec681f3Smrg   }
3557ec681f3Smrg
3567ec681f3Smrg   ralloc_free(disasm_info);
3577ec681f3Smrg
3587ec681f3Smrg   if (output_type == OPT_OUTPUT_C_LITERAL)
3597ec681f3Smrg      fprintf(output, "}");
3607ec681f3Smrg
3617ec681f3Smrg   result = EXIT_SUCCESS;
3627ec681f3Smrg   goto end;
3637ec681f3Smrg
3647ec681f3Smrgend:
3657ec681f3Smrg   free(input_filename);
3667ec681f3Smrg   free(output_file);
3677ec681f3Smrg
3687ec681f3Smrg   if (yyin)
3697ec681f3Smrg      fclose(yyin);
3707ec681f3Smrg
3717ec681f3Smrg   if (output)
3727ec681f3Smrg      fclose(output);
3737ec681f3Smrg
3747ec681f3Smrg   if (p)
3757ec681f3Smrg      ralloc_free(p);
3767ec681f3Smrg
3777ec681f3Smrg   if (devinfo)
3787ec681f3Smrg      free(devinfo);
3797ec681f3Smrg
3807ec681f3Smrg   exit(result);
3817ec681f3Smrg}
382