17ec681f3Smrg/*
27ec681f3Smrg * Copyright © 2021 Google, Inc.
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#include <assert.h>
257ec681f3Smrg#include <ctype.h>
267ec681f3Smrg#include <inttypes.h>
277ec681f3Smrg#include <stdio.h>
287ec681f3Smrg#include <stdlib.h>
297ec681f3Smrg#include <termios.h>
307ec681f3Smrg#include <unistd.h>
317ec681f3Smrg
327ec681f3Smrg#include "freedreno_pm4.h"
337ec681f3Smrg
347ec681f3Smrg#include "emu.h"
357ec681f3Smrg#include "util.h"
367ec681f3Smrg
377ec681f3Smrg/*
387ec681f3Smrg * Emulator User Interface:
397ec681f3Smrg *
407ec681f3Smrg * Handles the user prompts and input parsing.
417ec681f3Smrg */
427ec681f3Smrg
437ec681f3Smrgstatic void
447ec681f3Smrgclear_line(void)
457ec681f3Smrg{
467ec681f3Smrg   if (!isatty(STDOUT_FILENO))
477ec681f3Smrg      return;
487ec681f3Smrg   printf("\r                                                           \r");
497ec681f3Smrg}
507ec681f3Smrg
517ec681f3Smrgstatic int
527ec681f3Smrgreadchar(void)
537ec681f3Smrg{
547ec681f3Smrg   static struct termios saved_termios, unbuffered_termios;
557ec681f3Smrg   int c;
567ec681f3Smrg
577ec681f3Smrg   fflush(stdout);
587ec681f3Smrg
597ec681f3Smrg   tcgetattr(STDIN_FILENO, &saved_termios);
607ec681f3Smrg   unbuffered_termios = saved_termios;
617ec681f3Smrg   cfmakeraw(&unbuffered_termios);
627ec681f3Smrg
637ec681f3Smrg   tcsetattr(STDIN_FILENO, TCSANOW, &unbuffered_termios);
647ec681f3Smrg   do {
657ec681f3Smrg      c = getchar();
667ec681f3Smrg   } while (isspace(c));
677ec681f3Smrg   tcsetattr(STDIN_FILENO, TCSANOW, &saved_termios);
687ec681f3Smrg
697ec681f3Smrg   /* TODO, read from script until EOF and then read from stdin: */
707ec681f3Smrg   if (c == -1)
717ec681f3Smrg      exit(0);
727ec681f3Smrg
737ec681f3Smrg   return c;
747ec681f3Smrg}
757ec681f3Smrg
767ec681f3Smrgstatic const char *
777ec681f3Smrgextract_string(char **buf)
787ec681f3Smrg{
797ec681f3Smrg   char *p = *buf;
807ec681f3Smrg
817ec681f3Smrg   /* eat any leading whitespace: */
827ec681f3Smrg   while (*p && isspace(*p))
837ec681f3Smrg      p++;
847ec681f3Smrg
857ec681f3Smrg   if (!*p)
867ec681f3Smrg      return NULL;
877ec681f3Smrg
887ec681f3Smrg   char *ret = p;
897ec681f3Smrg
907ec681f3Smrg   /* skip to next whitespace: */
917ec681f3Smrg   while (*p && !isspace(*p))
927ec681f3Smrg      p++;
937ec681f3Smrg
947ec681f3Smrg   if (*p)
957ec681f3Smrg      *p = '\0';
967ec681f3Smrg
977ec681f3Smrg   *buf = ++p;
987ec681f3Smrg
997ec681f3Smrg   return ret;
1007ec681f3Smrg}
1017ec681f3Smrg
1027ec681f3Smrgstatic size_t
1037ec681f3Smrgreadline(char **p)
1047ec681f3Smrg{
1057ec681f3Smrg   static char *buf;
1067ec681f3Smrg   static size_t n;
1077ec681f3Smrg
1087ec681f3Smrg   ssize_t ret = getline(&buf, &n, stdin);
1097ec681f3Smrg   if (ret < 0)
1107ec681f3Smrg      return ret;
1117ec681f3Smrg
1127ec681f3Smrg   *p = buf;
1137ec681f3Smrg   return 0;
1147ec681f3Smrg}
1157ec681f3Smrg
1167ec681f3Smrgstatic ssize_t
1177ec681f3Smrgread_two_values(const char **val1, const char **val2)
1187ec681f3Smrg{
1197ec681f3Smrg   char *p;
1207ec681f3Smrg
1217ec681f3Smrg   ssize_t ret = readline(&p);
1227ec681f3Smrg   if (ret < 0)
1237ec681f3Smrg      return ret;
1247ec681f3Smrg
1257ec681f3Smrg   *val1 = extract_string(&p);
1267ec681f3Smrg   *val2 = extract_string(&p);
1277ec681f3Smrg
1287ec681f3Smrg   return 0;
1297ec681f3Smrg}
1307ec681f3Smrg
1317ec681f3Smrgstatic ssize_t
1327ec681f3Smrgread_one_value(const char **val)
1337ec681f3Smrg{
1347ec681f3Smrg   char *p;
1357ec681f3Smrg
1367ec681f3Smrg   ssize_t ret = readline(&p);
1377ec681f3Smrg   if (ret < 0)
1387ec681f3Smrg      return ret;
1397ec681f3Smrg
1407ec681f3Smrg   *val = extract_string(&p);
1417ec681f3Smrg
1427ec681f3Smrg   return 0;
1437ec681f3Smrg}
1447ec681f3Smrg
1457ec681f3Smrgstatic void
1467ec681f3Smrgdump_gpr_register(struct emu *emu, unsigned n)
1477ec681f3Smrg{
1487ec681f3Smrg   printf("              GPR:  ");
1497ec681f3Smrg   print_dst(n);
1507ec681f3Smrg   printf(": ");
1517ec681f3Smrg   if (BITSET_TEST(emu->gpr_regs.written, n)) {
1527ec681f3Smrg      printdelta("%08x\n", emu->gpr_regs.val[n]);
1537ec681f3Smrg   } else {
1547ec681f3Smrg      printf("%08x\n", emu->gpr_regs.val[n]);
1557ec681f3Smrg   }
1567ec681f3Smrg}
1577ec681f3Smrg
1587ec681f3Smrgstatic void
1597ec681f3Smrgdump_gpr_registers(struct emu *emu)
1607ec681f3Smrg{
1617ec681f3Smrg   for (unsigned i = 0; i < ARRAY_SIZE(emu->gpr_regs.val); i++) {
1627ec681f3Smrg      dump_gpr_register(emu, i);
1637ec681f3Smrg   }
1647ec681f3Smrg}
1657ec681f3Smrg
1667ec681f3Smrgstatic void
1677ec681f3Smrgdump_gpu_register(struct emu *emu, unsigned n)
1687ec681f3Smrg{
1697ec681f3Smrg   printf("              GPU:  ");
1707ec681f3Smrg   char *name = afuc_gpu_reg_name(n);
1717ec681f3Smrg   if (name) {
1727ec681f3Smrg      printf("%s", name);
1737ec681f3Smrg      free(name);
1747ec681f3Smrg   } else {
1757ec681f3Smrg      printf("0x%04x", n);
1767ec681f3Smrg   }
1777ec681f3Smrg   printf(": ");
1787ec681f3Smrg   if (BITSET_TEST(emu->gpu_regs.written, n)) {
1797ec681f3Smrg      printdelta("%08x\n", emu->gpu_regs.val[n]);
1807ec681f3Smrg   } else {
1817ec681f3Smrg      printf("%08x\n", emu->gpu_regs.val[n]);
1827ec681f3Smrg   }
1837ec681f3Smrg}
1847ec681f3Smrg
1857ec681f3Smrgstatic void
1867ec681f3Smrgdump_pipe_register(struct emu *emu, unsigned n)
1877ec681f3Smrg{
1887ec681f3Smrg   printf("              PIPE: ");
1897ec681f3Smrg   print_pipe_reg(n);
1907ec681f3Smrg   printf(": ");
1917ec681f3Smrg   if (BITSET_TEST(emu->pipe_regs.written, n)) {
1927ec681f3Smrg      printdelta("%08x\n", emu->pipe_regs.val[n]);
1937ec681f3Smrg   } else {
1947ec681f3Smrg      printf("%08x\n", emu->pipe_regs.val[n]);
1957ec681f3Smrg   }
1967ec681f3Smrg}
1977ec681f3Smrg
1987ec681f3Smrgstatic void
1997ec681f3Smrgdump_control_register(struct emu *emu, unsigned n)
2007ec681f3Smrg{
2017ec681f3Smrg   printf("              CTRL: ");
2027ec681f3Smrg   print_control_reg(n);
2037ec681f3Smrg   printf(": ");
2047ec681f3Smrg   if (BITSET_TEST(emu->control_regs.written, n)) {
2057ec681f3Smrg      printdelta("%08x\n", emu->control_regs.val[n]);
2067ec681f3Smrg   } else {
2077ec681f3Smrg      printf("%08x\n", emu->control_regs.val[n]);
2087ec681f3Smrg   }
2097ec681f3Smrg}
2107ec681f3Smrg
2117ec681f3Smrgstatic void
2127ec681f3Smrgdump_gpumem(struct emu *emu, uintptr_t addr)
2137ec681f3Smrg{
2147ec681f3Smrg   uint32_t val = emu_mem_read_dword(emu, addr);
2157ec681f3Smrg
2167ec681f3Smrg   printf("              MEM:  0x%016"PRIxPTR": ", addr);
2177ec681f3Smrg   if (addr == emu->gpumem_written) {
2187ec681f3Smrg      printdelta("0x%08x\n", val);
2197ec681f3Smrg   } else {
2207ec681f3Smrg      printf("0x%08x\n", val);
2217ec681f3Smrg   }
2227ec681f3Smrg}
2237ec681f3Smrg
2247ec681f3Smrgstatic void
2257ec681f3Smrgemu_write_gpr_prompt(struct emu *emu)
2267ec681f3Smrg{
2277ec681f3Smrg   clear_line();
2287ec681f3Smrg   printf("    GPR register (name or offset) and value: ");
2297ec681f3Smrg
2307ec681f3Smrg   const char *name;
2317ec681f3Smrg   const char *value;
2327ec681f3Smrg
2337ec681f3Smrg   if (read_two_values(&name, &value))
2347ec681f3Smrg      return;
2357ec681f3Smrg
2367ec681f3Smrg   unsigned offset = afuc_gpr_reg(name);
2377ec681f3Smrg   uint32_t val = strtoul(value, NULL, 0);
2387ec681f3Smrg
2397ec681f3Smrg   emu_set_gpr_reg(emu, offset, val);
2407ec681f3Smrg}
2417ec681f3Smrg
2427ec681f3Smrgstatic void
2437ec681f3Smrgemu_write_control_prompt(struct emu *emu)
2447ec681f3Smrg{
2457ec681f3Smrg   clear_line();
2467ec681f3Smrg   printf("    Control register (name or offset) and value: ");
2477ec681f3Smrg
2487ec681f3Smrg   const char *name;
2497ec681f3Smrg   const char *value;
2507ec681f3Smrg
2517ec681f3Smrg   if (read_two_values(&name, &value))
2527ec681f3Smrg      return;
2537ec681f3Smrg
2547ec681f3Smrg   unsigned offset = afuc_control_reg(name);
2557ec681f3Smrg   uint32_t val = strtoul(value, NULL, 0);
2567ec681f3Smrg
2577ec681f3Smrg   emu_set_control_reg(emu, offset, val);
2587ec681f3Smrg}
2597ec681f3Smrg
2607ec681f3Smrgstatic void
2617ec681f3Smrgemu_dump_control_prompt(struct emu *emu)
2627ec681f3Smrg{
2637ec681f3Smrg   clear_line();
2647ec681f3Smrg   printf("    Control register (name or offset): ");
2657ec681f3Smrg
2667ec681f3Smrg   const char *name;
2677ec681f3Smrg
2687ec681f3Smrg   if (read_one_value(&name))
2697ec681f3Smrg      return;
2707ec681f3Smrg
2717ec681f3Smrg   printf("\n");
2727ec681f3Smrg
2737ec681f3Smrg   unsigned offset = afuc_control_reg(name);
2747ec681f3Smrg   dump_control_register(emu, offset);
2757ec681f3Smrg}
2767ec681f3Smrg
2777ec681f3Smrgstatic void
2787ec681f3Smrgemu_write_gpu_prompt(struct emu *emu)
2797ec681f3Smrg{
2807ec681f3Smrg   clear_line();
2817ec681f3Smrg   printf("    GPU register (name or offset) and value: ");
2827ec681f3Smrg
2837ec681f3Smrg   const char *name;
2847ec681f3Smrg   const char *value;
2857ec681f3Smrg
2867ec681f3Smrg   if (read_two_values(&name, &value))
2877ec681f3Smrg      return;
2887ec681f3Smrg
2897ec681f3Smrg   unsigned offset = afuc_gpu_reg(name);
2907ec681f3Smrg   uint32_t val = strtoul(value, NULL, 0);
2917ec681f3Smrg
2927ec681f3Smrg   emu_set_gpu_reg(emu, offset, val);
2937ec681f3Smrg}
2947ec681f3Smrg
2957ec681f3Smrgstatic void
2967ec681f3Smrgemu_dump_gpu_prompt(struct emu *emu)
2977ec681f3Smrg{
2987ec681f3Smrg   clear_line();
2997ec681f3Smrg   printf("    GPU register (name or offset): ");
3007ec681f3Smrg
3017ec681f3Smrg   const char *name;
3027ec681f3Smrg
3037ec681f3Smrg   if (read_one_value(&name))
3047ec681f3Smrg      return;
3057ec681f3Smrg
3067ec681f3Smrg   printf("\n");
3077ec681f3Smrg
3087ec681f3Smrg   unsigned offset = afuc_gpu_reg(name);
3097ec681f3Smrg   dump_gpu_register(emu, offset);
3107ec681f3Smrg}
3117ec681f3Smrg
3127ec681f3Smrgstatic void
3137ec681f3Smrgemu_write_mem_prompt(struct emu *emu)
3147ec681f3Smrg{
3157ec681f3Smrg   clear_line();
3167ec681f3Smrg   printf("    GPU memory offset and value: ");
3177ec681f3Smrg
3187ec681f3Smrg   const char *offset;
3197ec681f3Smrg   const char *value;
3207ec681f3Smrg
3217ec681f3Smrg   if (read_two_values(&offset, &value))
3227ec681f3Smrg      return;
3237ec681f3Smrg
3247ec681f3Smrg   uintptr_t addr = strtoull(offset, NULL, 0);
3257ec681f3Smrg   uint32_t val = strtoul(value, NULL, 0);
3267ec681f3Smrg
3277ec681f3Smrg   emu_mem_write_dword(emu, addr, val);
3287ec681f3Smrg}
3297ec681f3Smrg
3307ec681f3Smrgstatic void
3317ec681f3Smrgemu_dump_mem_prompt(struct emu *emu)
3327ec681f3Smrg{
3337ec681f3Smrg   clear_line();
3347ec681f3Smrg   printf("    GPU memory offset: ");
3357ec681f3Smrg
3367ec681f3Smrg   const char *offset;
3377ec681f3Smrg
3387ec681f3Smrg   if (read_one_value(&offset))
3397ec681f3Smrg      return;
3407ec681f3Smrg
3417ec681f3Smrg   printf("\n");
3427ec681f3Smrg
3437ec681f3Smrg   uintptr_t addr = strtoull(offset, NULL, 0);
3447ec681f3Smrg   dump_gpumem(emu, addr);
3457ec681f3Smrg}
3467ec681f3Smrg
3477ec681f3Smrgstatic void
3487ec681f3Smrgemu_dump_prompt(struct emu *emu)
3497ec681f3Smrg{
3507ec681f3Smrg   do {
3517ec681f3Smrg      clear_line();
3527ec681f3Smrg      printf("  dump: GPR (r)egisters, (c)ontrol register, (g)pu register, (m)emory: ");
3537ec681f3Smrg
3547ec681f3Smrg      int c = readchar();
3557ec681f3Smrg      printf("%c\n", c);
3567ec681f3Smrg
3577ec681f3Smrg      if (c == 'r') {
3587ec681f3Smrg         /* Since there aren't too many GPR registers, just dump
3597ec681f3Smrg          * them all:
3607ec681f3Smrg          */
3617ec681f3Smrg         dump_gpr_registers(emu);
3627ec681f3Smrg         break;
3637ec681f3Smrg      } else if (c == 'c') {
3647ec681f3Smrg         emu_dump_control_prompt(emu);
3657ec681f3Smrg         break;
3667ec681f3Smrg      } else if (c == 'g') {
3677ec681f3Smrg         emu_dump_gpu_prompt(emu);
3687ec681f3Smrg         break;
3697ec681f3Smrg      } else if (c == 'm') {
3707ec681f3Smrg         emu_dump_mem_prompt(emu);
3717ec681f3Smrg         break;
3727ec681f3Smrg      } else {
3737ec681f3Smrg         printf("invalid option: '%c'\n", c);
3747ec681f3Smrg         break;
3757ec681f3Smrg      }
3767ec681f3Smrg   } while (true);
3777ec681f3Smrg}
3787ec681f3Smrg
3797ec681f3Smrgstatic void
3807ec681f3Smrgemu_write_prompt(struct emu *emu)
3817ec681f3Smrg{
3827ec681f3Smrg   do {
3837ec681f3Smrg      clear_line();
3847ec681f3Smrg      printf("  write: GPR (r)egister, (c)ontrol register, (g)pu register, (m)emory: ");
3857ec681f3Smrg
3867ec681f3Smrg      int c = readchar();
3877ec681f3Smrg      printf("%c\n", c);
3887ec681f3Smrg
3897ec681f3Smrg      if (c == 'r') {
3907ec681f3Smrg         emu_write_gpr_prompt(emu);
3917ec681f3Smrg         break;
3927ec681f3Smrg      } else if (c == 'c') {
3937ec681f3Smrg         emu_write_control_prompt(emu);
3947ec681f3Smrg         break;
3957ec681f3Smrg      } else if (c == 'g') {
3967ec681f3Smrg         emu_write_gpu_prompt(emu);
3977ec681f3Smrg         break;
3987ec681f3Smrg      } else if (c == 'm') {
3997ec681f3Smrg         emu_write_mem_prompt(emu);
4007ec681f3Smrg         break;
4017ec681f3Smrg      } else {
4027ec681f3Smrg         printf("invalid option: '%c'\n", c);
4037ec681f3Smrg         break;
4047ec681f3Smrg      }
4057ec681f3Smrg   } while (true);
4067ec681f3Smrg}
4077ec681f3Smrg
4087ec681f3Smrgstatic void
4097ec681f3Smrgemu_packet_prompt(struct emu *emu)
4107ec681f3Smrg{
4117ec681f3Smrg   clear_line();
4127ec681f3Smrg   printf("  Enter packet (opc or register name), followed by payload: ");
4137ec681f3Smrg   fflush(stdout);
4147ec681f3Smrg
4157ec681f3Smrg   char *p;
4167ec681f3Smrg   if (readline(&p) < 0)
4177ec681f3Smrg      return;
4187ec681f3Smrg
4197ec681f3Smrg   printf("\n");
4207ec681f3Smrg
4217ec681f3Smrg   const char *name = extract_string(&p);
4227ec681f3Smrg
4237ec681f3Smrg   /* Read the payload, so we can know the size to generate correct header: */
4247ec681f3Smrg   uint32_t payload[0x7f];
4257ec681f3Smrg   unsigned cnt = 0;
4267ec681f3Smrg
4277ec681f3Smrg   do {
4287ec681f3Smrg      const char *val = extract_string(&p);
4297ec681f3Smrg      if (!val)
4307ec681f3Smrg         break;
4317ec681f3Smrg
4327ec681f3Smrg      assert(cnt < ARRAY_SIZE(payload));
4337ec681f3Smrg      payload[cnt++] = strtoul(val, NULL, 0);
4347ec681f3Smrg   } while (true);
4357ec681f3Smrg
4367ec681f3Smrg   uint32_t hdr;
4377ec681f3Smrg   if (afuc_pm4_id(name) >= 0) {
4387ec681f3Smrg      unsigned opcode = afuc_pm4_id(name);
4397ec681f3Smrg      hdr = pm4_pkt7_hdr(opcode, cnt);
4407ec681f3Smrg   } else {
4417ec681f3Smrg      unsigned regindx = afuc_gpu_reg(name);
4427ec681f3Smrg      hdr = pm4_pkt4_hdr(regindx, cnt);
4437ec681f3Smrg   }
4447ec681f3Smrg
4457ec681f3Smrg   ASSERTED bool ret = emu_queue_push(&emu->roq, hdr);
4467ec681f3Smrg   assert(ret);
4477ec681f3Smrg
4487ec681f3Smrg   for (unsigned i = 0; i < cnt; i++) {
4497ec681f3Smrg      ASSERTED bool ret = emu_queue_push(&emu->roq, payload[i]);
4507ec681f3Smrg      assert(ret);
4517ec681f3Smrg   }
4527ec681f3Smrg}
4537ec681f3Smrg
4547ec681f3Smrgvoid
4557ec681f3Smrgemu_main_prompt(struct emu *emu)
4567ec681f3Smrg{
4577ec681f3Smrg   if (emu->run_mode)
4587ec681f3Smrg      return;
4597ec681f3Smrg
4607ec681f3Smrg   do {
4617ec681f3Smrg      clear_line();
4627ec681f3Smrg      printf("(s)tep, (r)un, (d)ump, (w)rite, (p)acket, (h)elp, (q)uit: ");
4637ec681f3Smrg
4647ec681f3Smrg      int c = readchar();
4657ec681f3Smrg
4667ec681f3Smrg      printf("%c\n", c);
4677ec681f3Smrg
4687ec681f3Smrg      if (c == 's') {
4697ec681f3Smrg         break;
4707ec681f3Smrg      } else if (c == 'r') {
4717ec681f3Smrg         emu->run_mode = true;
4727ec681f3Smrg         break;
4737ec681f3Smrg      } else if (c == 'd') {
4747ec681f3Smrg         emu_dump_prompt(emu);
4757ec681f3Smrg      } else if (c == 'w') {
4767ec681f3Smrg         emu_write_prompt(emu);
4777ec681f3Smrg      } else if (c == 'p') {
4787ec681f3Smrg         emu_packet_prompt(emu);
4797ec681f3Smrg      } else if (c == 'h') {
4807ec681f3Smrg         printf("  (s)tep   - single step to next instruction\n");
4817ec681f3Smrg         printf("  (r)un    - run until next waitin\n");
4827ec681f3Smrg         printf("  (d)ump   - dump memory/register menu\n");
4837ec681f3Smrg         printf("  (w)rite  - write memory/register menu\n");
4847ec681f3Smrg         printf("  (p)acket - inject a pm4 packet\n");
4857ec681f3Smrg         printf("  (h)elp   - show this usage message\n");
4867ec681f3Smrg         printf("  (q)uit   - exit emulator\n");
4877ec681f3Smrg      } else if (c == 'q') {
4887ec681f3Smrg         printf("\n");
4897ec681f3Smrg         exit(0);
4907ec681f3Smrg      } else {
4917ec681f3Smrg         printf("invalid option: '%c'\n", c);
4927ec681f3Smrg      }
4937ec681f3Smrg   } while (true);
4947ec681f3Smrg}
4957ec681f3Smrg
4967ec681f3Smrgvoid
4977ec681f3Smrgemu_clear_state_change(struct emu *emu)
4987ec681f3Smrg{
4997ec681f3Smrg   memset(emu->control_regs.written, 0, sizeof(emu->control_regs.written));
5007ec681f3Smrg   memset(emu->pipe_regs.written,    0, sizeof(emu->pipe_regs.written));
5017ec681f3Smrg   memset(emu->gpu_regs.written,     0, sizeof(emu->gpu_regs.written));
5027ec681f3Smrg   memset(emu->gpr_regs.written,     0, sizeof(emu->gpr_regs.written));
5037ec681f3Smrg   emu->gpumem_written = ~0;
5047ec681f3Smrg}
5057ec681f3Smrg
5067ec681f3Smrgvoid
5077ec681f3Smrgemu_dump_state_change(struct emu *emu)
5087ec681f3Smrg{
5097ec681f3Smrg   unsigned i;
5107ec681f3Smrg
5117ec681f3Smrg   if (emu->quiet)
5127ec681f3Smrg      return;
5137ec681f3Smrg
5147ec681f3Smrg   /* Print the GPRs that changed: */
5157ec681f3Smrg   BITSET_FOREACH_SET (i, emu->gpr_regs.written, EMU_NUM_GPR_REGS) {
5167ec681f3Smrg      dump_gpr_register(emu, i);
5177ec681f3Smrg   }
5187ec681f3Smrg
5197ec681f3Smrg   BITSET_FOREACH_SET (i, emu->gpu_regs.written, EMU_NUM_GPU_REGS) {
5207ec681f3Smrg      dump_gpu_register(emu, i);
5217ec681f3Smrg   }
5227ec681f3Smrg
5237ec681f3Smrg   BITSET_FOREACH_SET (i, emu->pipe_regs.written, EMU_NUM_PIPE_REGS) {
5247ec681f3Smrg      dump_pipe_register(emu, i);
5257ec681f3Smrg   }
5267ec681f3Smrg
5277ec681f3Smrg   BITSET_FOREACH_SET (i, emu->control_regs.written, EMU_NUM_CONTROL_REGS) {
5287ec681f3Smrg      dump_control_register(emu, i);
5297ec681f3Smrg   }
5307ec681f3Smrg
5317ec681f3Smrg   if (emu->gpumem_written != ~0) {
5327ec681f3Smrg      dump_gpumem(emu, emu->gpumem_written);
5337ec681f3Smrg   }
5347ec681f3Smrg}
535