1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © 2021 Google, Inc.
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13bf215546Sopenharmony_ci * Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20bf215546Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21bf215546Sopenharmony_ci * SOFTWARE.
22bf215546Sopenharmony_ci */
23bf215546Sopenharmony_ci
24bf215546Sopenharmony_ci#include <assert.h>
25bf215546Sopenharmony_ci#include <ctype.h>
26bf215546Sopenharmony_ci#include <inttypes.h>
27bf215546Sopenharmony_ci#include <stdio.h>
28bf215546Sopenharmony_ci#include <stdlib.h>
29bf215546Sopenharmony_ci#include <termios.h>
30bf215546Sopenharmony_ci#include <unistd.h>
31bf215546Sopenharmony_ci
32bf215546Sopenharmony_ci#include "freedreno_pm4.h"
33bf215546Sopenharmony_ci
34bf215546Sopenharmony_ci#include "emu.h"
35bf215546Sopenharmony_ci#include "util.h"
36bf215546Sopenharmony_ci
37bf215546Sopenharmony_ci/*
38bf215546Sopenharmony_ci * Emulator User Interface:
39bf215546Sopenharmony_ci *
40bf215546Sopenharmony_ci * Handles the user prompts and input parsing.
41bf215546Sopenharmony_ci */
42bf215546Sopenharmony_ci
43bf215546Sopenharmony_cistatic void
44bf215546Sopenharmony_ciclear_line(void)
45bf215546Sopenharmony_ci{
46bf215546Sopenharmony_ci   if (!isatty(STDOUT_FILENO))
47bf215546Sopenharmony_ci      return;
48bf215546Sopenharmony_ci   printf("\r                                                           \r");
49bf215546Sopenharmony_ci}
50bf215546Sopenharmony_ci
51bf215546Sopenharmony_cistatic int
52bf215546Sopenharmony_cireadchar(void)
53bf215546Sopenharmony_ci{
54bf215546Sopenharmony_ci   static struct termios saved_termios, unbuffered_termios;
55bf215546Sopenharmony_ci   int c;
56bf215546Sopenharmony_ci
57bf215546Sopenharmony_ci   fflush(stdout);
58bf215546Sopenharmony_ci
59bf215546Sopenharmony_ci   tcgetattr(STDIN_FILENO, &saved_termios);
60bf215546Sopenharmony_ci   unbuffered_termios = saved_termios;
61bf215546Sopenharmony_ci   cfmakeraw(&unbuffered_termios);
62bf215546Sopenharmony_ci
63bf215546Sopenharmony_ci   tcsetattr(STDIN_FILENO, TCSANOW, &unbuffered_termios);
64bf215546Sopenharmony_ci   do {
65bf215546Sopenharmony_ci      c = getchar();
66bf215546Sopenharmony_ci   } while (isspace(c));
67bf215546Sopenharmony_ci   tcsetattr(STDIN_FILENO, TCSANOW, &saved_termios);
68bf215546Sopenharmony_ci
69bf215546Sopenharmony_ci   /* TODO, read from script until EOF and then read from stdin: */
70bf215546Sopenharmony_ci   if (c == -1)
71bf215546Sopenharmony_ci      exit(0);
72bf215546Sopenharmony_ci
73bf215546Sopenharmony_ci   return c;
74bf215546Sopenharmony_ci}
75bf215546Sopenharmony_ci
76bf215546Sopenharmony_cistatic const char *
77bf215546Sopenharmony_ciextract_string(char **buf)
78bf215546Sopenharmony_ci{
79bf215546Sopenharmony_ci   char *p = *buf;
80bf215546Sopenharmony_ci
81bf215546Sopenharmony_ci   /* eat any leading whitespace: */
82bf215546Sopenharmony_ci   while (*p && isspace(*p))
83bf215546Sopenharmony_ci      p++;
84bf215546Sopenharmony_ci
85bf215546Sopenharmony_ci   if (!*p)
86bf215546Sopenharmony_ci      return NULL;
87bf215546Sopenharmony_ci
88bf215546Sopenharmony_ci   char *ret = p;
89bf215546Sopenharmony_ci
90bf215546Sopenharmony_ci   /* skip to next whitespace: */
91bf215546Sopenharmony_ci   while (*p && !isspace(*p))
92bf215546Sopenharmony_ci      p++;
93bf215546Sopenharmony_ci
94bf215546Sopenharmony_ci   if (*p)
95bf215546Sopenharmony_ci      *p = '\0';
96bf215546Sopenharmony_ci
97bf215546Sopenharmony_ci   *buf = ++p;
98bf215546Sopenharmony_ci
99bf215546Sopenharmony_ci   return ret;
100bf215546Sopenharmony_ci}
101bf215546Sopenharmony_ci
102bf215546Sopenharmony_cistatic size_t
103bf215546Sopenharmony_cireadline(char **p)
104bf215546Sopenharmony_ci{
105bf215546Sopenharmony_ci   static char *buf;
106bf215546Sopenharmony_ci   static size_t n;
107bf215546Sopenharmony_ci
108bf215546Sopenharmony_ci   ssize_t ret = getline(&buf, &n, stdin);
109bf215546Sopenharmony_ci   if (ret < 0)
110bf215546Sopenharmony_ci      return ret;
111bf215546Sopenharmony_ci
112bf215546Sopenharmony_ci   *p = buf;
113bf215546Sopenharmony_ci   return 0;
114bf215546Sopenharmony_ci}
115bf215546Sopenharmony_ci
116bf215546Sopenharmony_cistatic ssize_t
117bf215546Sopenharmony_ciread_two_values(const char **val1, const char **val2)
118bf215546Sopenharmony_ci{
119bf215546Sopenharmony_ci   char *p;
120bf215546Sopenharmony_ci
121bf215546Sopenharmony_ci   ssize_t ret = readline(&p);
122bf215546Sopenharmony_ci   if (ret < 0)
123bf215546Sopenharmony_ci      return ret;
124bf215546Sopenharmony_ci
125bf215546Sopenharmony_ci   *val1 = extract_string(&p);
126bf215546Sopenharmony_ci   *val2 = extract_string(&p);
127bf215546Sopenharmony_ci
128bf215546Sopenharmony_ci   return 0;
129bf215546Sopenharmony_ci}
130bf215546Sopenharmony_ci
131bf215546Sopenharmony_cistatic ssize_t
132bf215546Sopenharmony_ciread_one_value(const char **val)
133bf215546Sopenharmony_ci{
134bf215546Sopenharmony_ci   char *p;
135bf215546Sopenharmony_ci
136bf215546Sopenharmony_ci   ssize_t ret = readline(&p);
137bf215546Sopenharmony_ci   if (ret < 0)
138bf215546Sopenharmony_ci      return ret;
139bf215546Sopenharmony_ci
140bf215546Sopenharmony_ci   *val = extract_string(&p);
141bf215546Sopenharmony_ci
142bf215546Sopenharmony_ci   return 0;
143bf215546Sopenharmony_ci}
144bf215546Sopenharmony_ci
145bf215546Sopenharmony_cistatic void
146bf215546Sopenharmony_cidump_gpr_register(struct emu *emu, unsigned n)
147bf215546Sopenharmony_ci{
148bf215546Sopenharmony_ci   printf("              GPR:  ");
149bf215546Sopenharmony_ci   print_dst(n);
150bf215546Sopenharmony_ci   printf(": ");
151bf215546Sopenharmony_ci   if (BITSET_TEST(emu->gpr_regs.written, n)) {
152bf215546Sopenharmony_ci      printdelta("%08x\n", emu->gpr_regs.val[n]);
153bf215546Sopenharmony_ci   } else {
154bf215546Sopenharmony_ci      printf("%08x\n", emu->gpr_regs.val[n]);
155bf215546Sopenharmony_ci   }
156bf215546Sopenharmony_ci}
157bf215546Sopenharmony_ci
158bf215546Sopenharmony_cistatic void
159bf215546Sopenharmony_cidump_gpr_registers(struct emu *emu)
160bf215546Sopenharmony_ci{
161bf215546Sopenharmony_ci   for (unsigned i = 0; i < ARRAY_SIZE(emu->gpr_regs.val); i++) {
162bf215546Sopenharmony_ci      dump_gpr_register(emu, i);
163bf215546Sopenharmony_ci   }
164bf215546Sopenharmony_ci}
165bf215546Sopenharmony_ci
166bf215546Sopenharmony_cistatic void
167bf215546Sopenharmony_cidump_gpu_register(struct emu *emu, unsigned n)
168bf215546Sopenharmony_ci{
169bf215546Sopenharmony_ci   printf("              GPU:  ");
170bf215546Sopenharmony_ci   char *name = afuc_gpu_reg_name(n);
171bf215546Sopenharmony_ci   if (name) {
172bf215546Sopenharmony_ci      printf("%s", name);
173bf215546Sopenharmony_ci      free(name);
174bf215546Sopenharmony_ci   } else {
175bf215546Sopenharmony_ci      printf("0x%04x", n);
176bf215546Sopenharmony_ci   }
177bf215546Sopenharmony_ci   printf(": ");
178bf215546Sopenharmony_ci   if (BITSET_TEST(emu->gpu_regs.written, n)) {
179bf215546Sopenharmony_ci      printdelta("%08x\n", emu->gpu_regs.val[n]);
180bf215546Sopenharmony_ci   } else {
181bf215546Sopenharmony_ci      printf("%08x\n", emu->gpu_regs.val[n]);
182bf215546Sopenharmony_ci   }
183bf215546Sopenharmony_ci}
184bf215546Sopenharmony_ci
185bf215546Sopenharmony_cistatic void
186bf215546Sopenharmony_cidump_pipe_register(struct emu *emu, unsigned n)
187bf215546Sopenharmony_ci{
188bf215546Sopenharmony_ci   printf("              PIPE: ");
189bf215546Sopenharmony_ci   print_pipe_reg(n);
190bf215546Sopenharmony_ci   printf(": ");
191bf215546Sopenharmony_ci   if (BITSET_TEST(emu->pipe_regs.written, n)) {
192bf215546Sopenharmony_ci      printdelta("%08x\n", emu->pipe_regs.val[n]);
193bf215546Sopenharmony_ci   } else {
194bf215546Sopenharmony_ci      printf("%08x\n", emu->pipe_regs.val[n]);
195bf215546Sopenharmony_ci   }
196bf215546Sopenharmony_ci}
197bf215546Sopenharmony_ci
198bf215546Sopenharmony_cistatic void
199bf215546Sopenharmony_cidump_control_register(struct emu *emu, unsigned n)
200bf215546Sopenharmony_ci{
201bf215546Sopenharmony_ci   printf("              CTRL: ");
202bf215546Sopenharmony_ci   print_control_reg(n);
203bf215546Sopenharmony_ci   printf(": ");
204bf215546Sopenharmony_ci   if (BITSET_TEST(emu->control_regs.written, n)) {
205bf215546Sopenharmony_ci      printdelta("%08x\n", emu->control_regs.val[n]);
206bf215546Sopenharmony_ci   } else {
207bf215546Sopenharmony_ci      printf("%08x\n", emu->control_regs.val[n]);
208bf215546Sopenharmony_ci   }
209bf215546Sopenharmony_ci}
210bf215546Sopenharmony_ci
211bf215546Sopenharmony_cistatic void
212bf215546Sopenharmony_cidump_gpumem(struct emu *emu, uintptr_t addr)
213bf215546Sopenharmony_ci{
214bf215546Sopenharmony_ci   uint32_t val = emu_mem_read_dword(emu, addr);
215bf215546Sopenharmony_ci
216bf215546Sopenharmony_ci   printf("              MEM:  0x%016"PRIxPTR": ", addr);
217bf215546Sopenharmony_ci   if (addr == emu->gpumem_written) {
218bf215546Sopenharmony_ci      printdelta("0x%08x\n", val);
219bf215546Sopenharmony_ci   } else {
220bf215546Sopenharmony_ci      printf("0x%08x\n", val);
221bf215546Sopenharmony_ci   }
222bf215546Sopenharmony_ci}
223bf215546Sopenharmony_ci
224bf215546Sopenharmony_cistatic void
225bf215546Sopenharmony_ciemu_write_gpr_prompt(struct emu *emu)
226bf215546Sopenharmony_ci{
227bf215546Sopenharmony_ci   clear_line();
228bf215546Sopenharmony_ci   printf("    GPR register (name or offset) and value: ");
229bf215546Sopenharmony_ci
230bf215546Sopenharmony_ci   const char *name;
231bf215546Sopenharmony_ci   const char *value;
232bf215546Sopenharmony_ci
233bf215546Sopenharmony_ci   if (read_two_values(&name, &value))
234bf215546Sopenharmony_ci      return;
235bf215546Sopenharmony_ci
236bf215546Sopenharmony_ci   unsigned offset = afuc_gpr_reg(name);
237bf215546Sopenharmony_ci   uint32_t val = strtoul(value, NULL, 0);
238bf215546Sopenharmony_ci
239bf215546Sopenharmony_ci   emu_set_gpr_reg(emu, offset, val);
240bf215546Sopenharmony_ci}
241bf215546Sopenharmony_ci
242bf215546Sopenharmony_cistatic void
243bf215546Sopenharmony_ciemu_write_control_prompt(struct emu *emu)
244bf215546Sopenharmony_ci{
245bf215546Sopenharmony_ci   clear_line();
246bf215546Sopenharmony_ci   printf("    Control register (name or offset) and value: ");
247bf215546Sopenharmony_ci
248bf215546Sopenharmony_ci   const char *name;
249bf215546Sopenharmony_ci   const char *value;
250bf215546Sopenharmony_ci
251bf215546Sopenharmony_ci   if (read_two_values(&name, &value))
252bf215546Sopenharmony_ci      return;
253bf215546Sopenharmony_ci
254bf215546Sopenharmony_ci   unsigned offset = afuc_control_reg(name);
255bf215546Sopenharmony_ci   uint32_t val = strtoul(value, NULL, 0);
256bf215546Sopenharmony_ci
257bf215546Sopenharmony_ci   emu_set_control_reg(emu, offset, val);
258bf215546Sopenharmony_ci}
259bf215546Sopenharmony_ci
260bf215546Sopenharmony_cistatic void
261bf215546Sopenharmony_ciemu_dump_control_prompt(struct emu *emu)
262bf215546Sopenharmony_ci{
263bf215546Sopenharmony_ci   clear_line();
264bf215546Sopenharmony_ci   printf("    Control register (name or offset): ");
265bf215546Sopenharmony_ci
266bf215546Sopenharmony_ci   const char *name;
267bf215546Sopenharmony_ci
268bf215546Sopenharmony_ci   if (read_one_value(&name))
269bf215546Sopenharmony_ci      return;
270bf215546Sopenharmony_ci
271bf215546Sopenharmony_ci   printf("\n");
272bf215546Sopenharmony_ci
273bf215546Sopenharmony_ci   unsigned offset = afuc_control_reg(name);
274bf215546Sopenharmony_ci   dump_control_register(emu, offset);
275bf215546Sopenharmony_ci}
276bf215546Sopenharmony_ci
277bf215546Sopenharmony_cistatic void
278bf215546Sopenharmony_ciemu_write_gpu_prompt(struct emu *emu)
279bf215546Sopenharmony_ci{
280bf215546Sopenharmony_ci   clear_line();
281bf215546Sopenharmony_ci   printf("    GPU register (name or offset) and value: ");
282bf215546Sopenharmony_ci
283bf215546Sopenharmony_ci   const char *name;
284bf215546Sopenharmony_ci   const char *value;
285bf215546Sopenharmony_ci
286bf215546Sopenharmony_ci   if (read_two_values(&name, &value))
287bf215546Sopenharmony_ci      return;
288bf215546Sopenharmony_ci
289bf215546Sopenharmony_ci   unsigned offset = afuc_gpu_reg(name);
290bf215546Sopenharmony_ci   uint32_t val = strtoul(value, NULL, 0);
291bf215546Sopenharmony_ci
292bf215546Sopenharmony_ci   emu_set_gpu_reg(emu, offset, val);
293bf215546Sopenharmony_ci}
294bf215546Sopenharmony_ci
295bf215546Sopenharmony_cistatic void
296bf215546Sopenharmony_ciemu_dump_gpu_prompt(struct emu *emu)
297bf215546Sopenharmony_ci{
298bf215546Sopenharmony_ci   clear_line();
299bf215546Sopenharmony_ci   printf("    GPU register (name or offset): ");
300bf215546Sopenharmony_ci
301bf215546Sopenharmony_ci   const char *name;
302bf215546Sopenharmony_ci
303bf215546Sopenharmony_ci   if (read_one_value(&name))
304bf215546Sopenharmony_ci      return;
305bf215546Sopenharmony_ci
306bf215546Sopenharmony_ci   printf("\n");
307bf215546Sopenharmony_ci
308bf215546Sopenharmony_ci   unsigned offset = afuc_gpu_reg(name);
309bf215546Sopenharmony_ci   dump_gpu_register(emu, offset);
310bf215546Sopenharmony_ci}
311bf215546Sopenharmony_ci
312bf215546Sopenharmony_cistatic void
313bf215546Sopenharmony_ciemu_write_mem_prompt(struct emu *emu)
314bf215546Sopenharmony_ci{
315bf215546Sopenharmony_ci   clear_line();
316bf215546Sopenharmony_ci   printf("    GPU memory offset and value: ");
317bf215546Sopenharmony_ci
318bf215546Sopenharmony_ci   const char *offset;
319bf215546Sopenharmony_ci   const char *value;
320bf215546Sopenharmony_ci
321bf215546Sopenharmony_ci   if (read_two_values(&offset, &value))
322bf215546Sopenharmony_ci      return;
323bf215546Sopenharmony_ci
324bf215546Sopenharmony_ci   uintptr_t addr = strtoull(offset, NULL, 0);
325bf215546Sopenharmony_ci   uint32_t val = strtoul(value, NULL, 0);
326bf215546Sopenharmony_ci
327bf215546Sopenharmony_ci   emu_mem_write_dword(emu, addr, val);
328bf215546Sopenharmony_ci}
329bf215546Sopenharmony_ci
330bf215546Sopenharmony_cistatic void
331bf215546Sopenharmony_ciemu_dump_mem_prompt(struct emu *emu)
332bf215546Sopenharmony_ci{
333bf215546Sopenharmony_ci   clear_line();
334bf215546Sopenharmony_ci   printf("    GPU memory offset: ");
335bf215546Sopenharmony_ci
336bf215546Sopenharmony_ci   const char *offset;
337bf215546Sopenharmony_ci
338bf215546Sopenharmony_ci   if (read_one_value(&offset))
339bf215546Sopenharmony_ci      return;
340bf215546Sopenharmony_ci
341bf215546Sopenharmony_ci   printf("\n");
342bf215546Sopenharmony_ci
343bf215546Sopenharmony_ci   uintptr_t addr = strtoull(offset, NULL, 0);
344bf215546Sopenharmony_ci   dump_gpumem(emu, addr);
345bf215546Sopenharmony_ci}
346bf215546Sopenharmony_ci
347bf215546Sopenharmony_cistatic void
348bf215546Sopenharmony_ciemu_dump_prompt(struct emu *emu)
349bf215546Sopenharmony_ci{
350bf215546Sopenharmony_ci   do {
351bf215546Sopenharmony_ci      clear_line();
352bf215546Sopenharmony_ci      printf("  dump: GPR (r)egisters, (c)ontrol register, (g)pu register, (m)emory: ");
353bf215546Sopenharmony_ci
354bf215546Sopenharmony_ci      int c = readchar();
355bf215546Sopenharmony_ci      printf("%c\n", c);
356bf215546Sopenharmony_ci
357bf215546Sopenharmony_ci      if (c == 'r') {
358bf215546Sopenharmony_ci         /* Since there aren't too many GPR registers, just dump
359bf215546Sopenharmony_ci          * them all:
360bf215546Sopenharmony_ci          */
361bf215546Sopenharmony_ci         dump_gpr_registers(emu);
362bf215546Sopenharmony_ci         break;
363bf215546Sopenharmony_ci      } else if (c == 'c') {
364bf215546Sopenharmony_ci         emu_dump_control_prompt(emu);
365bf215546Sopenharmony_ci         break;
366bf215546Sopenharmony_ci      } else if (c == 'g') {
367bf215546Sopenharmony_ci         emu_dump_gpu_prompt(emu);
368bf215546Sopenharmony_ci         break;
369bf215546Sopenharmony_ci      } else if (c == 'm') {
370bf215546Sopenharmony_ci         emu_dump_mem_prompt(emu);
371bf215546Sopenharmony_ci         break;
372bf215546Sopenharmony_ci      } else {
373bf215546Sopenharmony_ci         printf("invalid option: '%c'\n", c);
374bf215546Sopenharmony_ci         break;
375bf215546Sopenharmony_ci      }
376bf215546Sopenharmony_ci   } while (true);
377bf215546Sopenharmony_ci}
378bf215546Sopenharmony_ci
379bf215546Sopenharmony_cistatic void
380bf215546Sopenharmony_ciemu_write_prompt(struct emu *emu)
381bf215546Sopenharmony_ci{
382bf215546Sopenharmony_ci   do {
383bf215546Sopenharmony_ci      clear_line();
384bf215546Sopenharmony_ci      printf("  write: GPR (r)egister, (c)ontrol register, (g)pu register, (m)emory: ");
385bf215546Sopenharmony_ci
386bf215546Sopenharmony_ci      int c = readchar();
387bf215546Sopenharmony_ci      printf("%c\n", c);
388bf215546Sopenharmony_ci
389bf215546Sopenharmony_ci      if (c == 'r') {
390bf215546Sopenharmony_ci         emu_write_gpr_prompt(emu);
391bf215546Sopenharmony_ci         break;
392bf215546Sopenharmony_ci      } else if (c == 'c') {
393bf215546Sopenharmony_ci         emu_write_control_prompt(emu);
394bf215546Sopenharmony_ci         break;
395bf215546Sopenharmony_ci      } else if (c == 'g') {
396bf215546Sopenharmony_ci         emu_write_gpu_prompt(emu);
397bf215546Sopenharmony_ci         break;
398bf215546Sopenharmony_ci      } else if (c == 'm') {
399bf215546Sopenharmony_ci         emu_write_mem_prompt(emu);
400bf215546Sopenharmony_ci         break;
401bf215546Sopenharmony_ci      } else {
402bf215546Sopenharmony_ci         printf("invalid option: '%c'\n", c);
403bf215546Sopenharmony_ci         break;
404bf215546Sopenharmony_ci      }
405bf215546Sopenharmony_ci   } while (true);
406bf215546Sopenharmony_ci}
407bf215546Sopenharmony_ci
408bf215546Sopenharmony_cistatic void
409bf215546Sopenharmony_ciemu_packet_prompt(struct emu *emu)
410bf215546Sopenharmony_ci{
411bf215546Sopenharmony_ci   clear_line();
412bf215546Sopenharmony_ci   printf("  Enter packet (opc or register name), followed by payload: ");
413bf215546Sopenharmony_ci   fflush(stdout);
414bf215546Sopenharmony_ci
415bf215546Sopenharmony_ci   char *p;
416bf215546Sopenharmony_ci   if (readline(&p) < 0)
417bf215546Sopenharmony_ci      return;
418bf215546Sopenharmony_ci
419bf215546Sopenharmony_ci   printf("\n");
420bf215546Sopenharmony_ci
421bf215546Sopenharmony_ci   const char *name = extract_string(&p);
422bf215546Sopenharmony_ci
423bf215546Sopenharmony_ci   /* Read the payload, so we can know the size to generate correct header: */
424bf215546Sopenharmony_ci   uint32_t payload[0x7f];
425bf215546Sopenharmony_ci   unsigned cnt = 0;
426bf215546Sopenharmony_ci
427bf215546Sopenharmony_ci   do {
428bf215546Sopenharmony_ci      const char *val = extract_string(&p);
429bf215546Sopenharmony_ci      if (!val)
430bf215546Sopenharmony_ci         break;
431bf215546Sopenharmony_ci
432bf215546Sopenharmony_ci      assert(cnt < ARRAY_SIZE(payload));
433bf215546Sopenharmony_ci      payload[cnt++] = strtoul(val, NULL, 0);
434bf215546Sopenharmony_ci   } while (true);
435bf215546Sopenharmony_ci
436bf215546Sopenharmony_ci   uint32_t hdr;
437bf215546Sopenharmony_ci   if (afuc_pm4_id(name) >= 0) {
438bf215546Sopenharmony_ci      unsigned opcode = afuc_pm4_id(name);
439bf215546Sopenharmony_ci      hdr = pm4_pkt7_hdr(opcode, cnt);
440bf215546Sopenharmony_ci   } else {
441bf215546Sopenharmony_ci      unsigned regindx = afuc_gpu_reg(name);
442bf215546Sopenharmony_ci      hdr = pm4_pkt4_hdr(regindx, cnt);
443bf215546Sopenharmony_ci   }
444bf215546Sopenharmony_ci
445bf215546Sopenharmony_ci   ASSERTED bool ret = emu_queue_push(&emu->roq, hdr);
446bf215546Sopenharmony_ci   assert(ret);
447bf215546Sopenharmony_ci
448bf215546Sopenharmony_ci   for (unsigned i = 0; i < cnt; i++) {
449bf215546Sopenharmony_ci      ASSERTED bool ret = emu_queue_push(&emu->roq, payload[i]);
450bf215546Sopenharmony_ci      assert(ret);
451bf215546Sopenharmony_ci   }
452bf215546Sopenharmony_ci}
453bf215546Sopenharmony_ci
454bf215546Sopenharmony_civoid
455bf215546Sopenharmony_ciemu_main_prompt(struct emu *emu)
456bf215546Sopenharmony_ci{
457bf215546Sopenharmony_ci   if (emu->run_mode)
458bf215546Sopenharmony_ci      return;
459bf215546Sopenharmony_ci
460bf215546Sopenharmony_ci   do {
461bf215546Sopenharmony_ci      clear_line();
462bf215546Sopenharmony_ci      printf("(s)tep, (r)un, (d)ump, (w)rite, (p)acket, (h)elp, (q)uit: ");
463bf215546Sopenharmony_ci
464bf215546Sopenharmony_ci      int c = readchar();
465bf215546Sopenharmony_ci
466bf215546Sopenharmony_ci      printf("%c\n", c);
467bf215546Sopenharmony_ci
468bf215546Sopenharmony_ci      if (c == 's') {
469bf215546Sopenharmony_ci         break;
470bf215546Sopenharmony_ci      } else if (c == 'r') {
471bf215546Sopenharmony_ci         emu->run_mode = true;
472bf215546Sopenharmony_ci         break;
473bf215546Sopenharmony_ci      } else if (c == 'd') {
474bf215546Sopenharmony_ci         emu_dump_prompt(emu);
475bf215546Sopenharmony_ci      } else if (c == 'w') {
476bf215546Sopenharmony_ci         emu_write_prompt(emu);
477bf215546Sopenharmony_ci      } else if (c == 'p') {
478bf215546Sopenharmony_ci         emu_packet_prompt(emu);
479bf215546Sopenharmony_ci      } else if (c == 'h') {
480bf215546Sopenharmony_ci         printf("  (s)tep   - single step to next instruction\n");
481bf215546Sopenharmony_ci         printf("  (r)un    - run until next waitin\n");
482bf215546Sopenharmony_ci         printf("  (d)ump   - dump memory/register menu\n");
483bf215546Sopenharmony_ci         printf("  (w)rite  - write memory/register menu\n");
484bf215546Sopenharmony_ci         printf("  (p)acket - inject a pm4 packet\n");
485bf215546Sopenharmony_ci         printf("  (h)elp   - show this usage message\n");
486bf215546Sopenharmony_ci         printf("  (q)uit   - exit emulator\n");
487bf215546Sopenharmony_ci      } else if (c == 'q') {
488bf215546Sopenharmony_ci         printf("\n");
489bf215546Sopenharmony_ci         exit(0);
490bf215546Sopenharmony_ci      } else {
491bf215546Sopenharmony_ci         printf("invalid option: '%c'\n", c);
492bf215546Sopenharmony_ci      }
493bf215546Sopenharmony_ci   } while (true);
494bf215546Sopenharmony_ci}
495bf215546Sopenharmony_ci
496bf215546Sopenharmony_civoid
497bf215546Sopenharmony_ciemu_clear_state_change(struct emu *emu)
498bf215546Sopenharmony_ci{
499bf215546Sopenharmony_ci   memset(emu->control_regs.written, 0, sizeof(emu->control_regs.written));
500bf215546Sopenharmony_ci   memset(emu->pipe_regs.written,    0, sizeof(emu->pipe_regs.written));
501bf215546Sopenharmony_ci   memset(emu->gpu_regs.written,     0, sizeof(emu->gpu_regs.written));
502bf215546Sopenharmony_ci   memset(emu->gpr_regs.written,     0, sizeof(emu->gpr_regs.written));
503bf215546Sopenharmony_ci   emu->gpumem_written = ~0;
504bf215546Sopenharmony_ci}
505bf215546Sopenharmony_ci
506bf215546Sopenharmony_civoid
507bf215546Sopenharmony_ciemu_dump_state_change(struct emu *emu)
508bf215546Sopenharmony_ci{
509bf215546Sopenharmony_ci   unsigned i;
510bf215546Sopenharmony_ci
511bf215546Sopenharmony_ci   if (emu->quiet)
512bf215546Sopenharmony_ci      return;
513bf215546Sopenharmony_ci
514bf215546Sopenharmony_ci   /* Print the GPRs that changed: */
515bf215546Sopenharmony_ci   BITSET_FOREACH_SET (i, emu->gpr_regs.written, EMU_NUM_GPR_REGS) {
516bf215546Sopenharmony_ci      dump_gpr_register(emu, i);
517bf215546Sopenharmony_ci   }
518bf215546Sopenharmony_ci
519bf215546Sopenharmony_ci   BITSET_FOREACH_SET (i, emu->gpu_regs.written, EMU_NUM_GPU_REGS) {
520bf215546Sopenharmony_ci      dump_gpu_register(emu, i);
521bf215546Sopenharmony_ci   }
522bf215546Sopenharmony_ci
523bf215546Sopenharmony_ci   BITSET_FOREACH_SET (i, emu->pipe_regs.written, EMU_NUM_PIPE_REGS) {
524bf215546Sopenharmony_ci      dump_pipe_register(emu, i);
525bf215546Sopenharmony_ci   }
526bf215546Sopenharmony_ci
527bf215546Sopenharmony_ci   BITSET_FOREACH_SET (i, emu->control_regs.written, EMU_NUM_CONTROL_REGS) {
528bf215546Sopenharmony_ci      dump_control_register(emu, i);
529bf215546Sopenharmony_ci   }
530bf215546Sopenharmony_ci
531bf215546Sopenharmony_ci   if (emu->gpumem_written != ~0) {
532bf215546Sopenharmony_ci      dump_gpumem(emu, emu->gpumem_written);
533bf215546Sopenharmony_ci   }
534bf215546Sopenharmony_ci}
535