xref: /aosp_15_r20/external/mesa3d/src/freedreno/afuc/emu-regs.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright © 2021 Google, Inc.
3  * SPDX-License-Identifier: MIT
4  */
5 
6 #include <assert.h>
7 #include <ctype.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 
11 #include "emu.h"
12 #include "util.h"
13 
14 /*
15  * Emulator Registers:
16  *
17  * Handles access to GPR, GPU, control, and pipe registers.
18  */
19 
20 static bool
is_draw_state_control_reg(unsigned n)21 is_draw_state_control_reg(unsigned n)
22 {
23    char *reg_name = afuc_control_reg_name(n);
24    if (!reg_name)
25       return false;
26    bool ret = !!strstr(reg_name, "DRAW_STATE");
27    free(reg_name);
28    return ret;
29 }
30 
31 uint32_t
emu_get_control_reg(struct emu * emu,unsigned n)32 emu_get_control_reg(struct emu *emu, unsigned n)
33 {
34    assert(n < ARRAY_SIZE(emu->control_regs.val));
35    if (is_draw_state_control_reg(n))
36       return emu_get_draw_state_reg(emu, n);
37    return emu->control_regs.val[n];
38 }
39 
40 void
emu_set_control_reg(struct emu * emu,unsigned n,uint32_t val)41 emu_set_control_reg(struct emu *emu, unsigned n, uint32_t val)
42 {
43    EMU_CONTROL_REG(PACKET_TABLE_WRITE);
44    EMU_CONTROL_REG(PACKET_TABLE_WRITE_ADDR);
45    EMU_CONTROL_REG(REG_WRITE);
46    EMU_CONTROL_REG(REG_WRITE_ADDR);
47    EMU_CONTROL_REG(BV_CNTL);
48    EMU_CONTROL_REG(LPAC_CNTL);
49    EMU_CONTROL_REG(THREAD_SYNC);
50 
51    assert(n < ARRAY_SIZE(emu->control_regs.val));
52    BITSET_SET(emu->control_regs.written, n);
53    emu->control_regs.val[n] = val;
54 
55    /* Some control regs have special action on write: */
56    if (n == emu_reg_offset(&PACKET_TABLE_WRITE)) {
57       unsigned write_addr = emu_get_reg32(emu, &PACKET_TABLE_WRITE_ADDR);
58 
59       assert(write_addr < ARRAY_SIZE(emu->jmptbl));
60       emu->jmptbl[write_addr] = val;
61 
62       emu_set_reg32(emu, &PACKET_TABLE_WRITE_ADDR, write_addr + 1);
63    } else if (n == emu_reg_offset(&REG_WRITE)) {
64       uint32_t write_addr = emu_get_reg32(emu, &REG_WRITE_ADDR);
65 
66       /* Upper bits seem like some flags, not part of the actual
67        * register offset.. not sure what they mean yet:
68        */
69       uint32_t flags = write_addr >> 16;
70       write_addr &= 0xffff;
71 
72       emu_set_gpu_reg(emu, write_addr++, val);
73       emu_set_reg32(emu, &REG_WRITE_ADDR, write_addr | (flags << 16));
74    } else if (gpuver >= 7 && n == emu_reg_offset(&BV_CNTL)) {
75       /* This is sort-of a hack, but emulate what the BV bootstrap routine
76        * does so that the main bootstrap routine doesn't get stuck.
77        */
78       emu_set_reg32(emu, &THREAD_SYNC,
79                     emu_get_reg32(emu, &THREAD_SYNC) & ~(1u << 1));
80    } else if (gpuver >= 7 && n == emu_reg_offset(&LPAC_CNTL)) {
81       /* This is sort-of a hack, but emulate what the LPAC bootstrap routine
82        * does so that the main bootstrap routine doesn't get stuck.
83        */
84       emu_set_reg32(emu, &THREAD_SYNC,
85                     emu_get_reg32(emu, &THREAD_SYNC) & ~(1u << 2));
86    } else if (is_draw_state_control_reg(n)) {
87       emu_set_draw_state_reg(emu, n, val);
88    }
89 }
90 
91 uint32_t
emu_get_sqe_reg(struct emu * emu,unsigned n)92 emu_get_sqe_reg(struct emu *emu, unsigned n)
93 {
94    assert(n < ARRAY_SIZE(emu->sqe_regs.val));
95    return emu->sqe_regs.val[n];
96 }
97 
98 void
emu_set_sqe_reg(struct emu * emu,unsigned n,uint32_t val)99 emu_set_sqe_reg(struct emu *emu, unsigned n, uint32_t val)
100 {
101    assert(n < ARRAY_SIZE(emu->sqe_regs.val));
102    BITSET_SET(emu->sqe_regs.written, n);
103    emu->sqe_regs.val[n] = val;
104 }
105 
106 static uint32_t
emu_get_pipe_reg(struct emu * emu,unsigned n)107 emu_get_pipe_reg(struct emu *emu, unsigned n)
108 {
109    assert(n < ARRAY_SIZE(emu->pipe_regs.val));
110    return emu->pipe_regs.val[n];
111 }
112 
113 static void
emu_set_pipe_reg(struct emu * emu,unsigned n,uint32_t val)114 emu_set_pipe_reg(struct emu *emu, unsigned n, uint32_t val)
115 {
116    EMU_PIPE_REG(NRT_DATA);
117    EMU_PIPE_REG(NRT_ADDR);
118 
119    assert(n < ARRAY_SIZE(emu->pipe_regs.val));
120    BITSET_SET(emu->pipe_regs.written, n);
121    emu->pipe_regs.val[n] = val;
122 
123    /* Some pipe regs have special action on write: */
124    if (n == emu_reg_offset(&NRT_DATA)) {
125       uintptr_t addr = emu_get_reg64(emu, &NRT_ADDR);
126 
127       emu_mem_write_dword(emu, addr, val);
128 
129       emu_set_reg64(emu, &NRT_ADDR, addr + 4);
130    }
131 }
132 
133 static uint32_t
emu_get_gpu_reg(struct emu * emu,unsigned n)134 emu_get_gpu_reg(struct emu *emu, unsigned n)
135 {
136    if (n >= ARRAY_SIZE(emu->gpu_regs.val))
137       return 0;
138    assert(n < ARRAY_SIZE(emu->gpu_regs.val));
139    return emu->gpu_regs.val[n];
140 }
141 
142 void
emu_set_gpu_reg(struct emu * emu,unsigned n,uint32_t val)143 emu_set_gpu_reg(struct emu *emu, unsigned n, uint32_t val)
144 {
145    EMU_GPU_REG(CP_LPAC_SQE_CNTL);
146    EMU_CONTROL_REG(THREAD_SYNC);
147 
148    if (n >= ARRAY_SIZE(emu->gpu_regs.val))
149       return;
150    assert(n < ARRAY_SIZE(emu->gpu_regs.val));
151    BITSET_SET(emu->gpu_regs.written, n);
152    emu->gpu_regs.val[n] = val;
153 
154    if (n == emu_reg_offset(&CP_LPAC_SQE_CNTL)) {
155       /* This is sort-of a hack, but emulate what the LPAC bootstrap routine
156        * does so that the main bootstrap routine doesn't get stuck.
157        */
158       emu_set_reg32(emu, &THREAD_SYNC,
159                     emu_get_reg32(emu, &THREAD_SYNC) | (1u << 1));
160    }
161 }
162 
163 static bool
is_pipe_reg_addr(unsigned regoff)164 is_pipe_reg_addr(unsigned regoff)
165 {
166    return regoff > 0xffff;
167 }
168 
169 static unsigned
get_reg_addr(struct emu * emu)170 get_reg_addr(struct emu *emu)
171 {
172    switch (emu->data_mode) {
173    case DATA_PIPE:
174    case DATA_ADDR:    return REG_ADDR;
175    case DATA_USRADDR: return REG_USRADDR;
176    default:
177       unreachable("bad data_mode");
178       return 0;
179    }
180 }
181 
182 /* Handle reads for special streaming regs: */
183 static uint32_t
emu_get_fifo_reg(struct emu * emu,unsigned n,bool peek)184 emu_get_fifo_reg(struct emu *emu, unsigned n, bool peek)
185 {
186    /* TODO the fifo regs are slurping out of a FIFO that the hw is filling
187     * in parallel.. we can use `struct emu_queue` to emulate what is actually
188     * happening more accurately
189     */
190 
191    if (n == REG_MEMDATA) {
192       /* $memdata */
193       EMU_CONTROL_REG(MEM_READ_DWORDS);
194       EMU_CONTROL_REG(MEM_READ_ADDR);
195       EMU_CONTROL_REG(MEM_READ_ADDR_HI_PRIVILEGED);
196 
197       unsigned  read_dwords = emu_get_reg32(emu, &MEM_READ_DWORDS);
198       uintptr_t read_addr   = emu_get_reg64(emu, &MEM_READ_ADDR);
199       uintptr_t read_addr_hi = 0;
200       if (emu->fw_id == AFUC_A750)
201          read_addr_hi = emu_get_reg64(emu, &MEM_READ_ADDR_HI_PRIVILEGED);
202 
203       /* We don't model privileged vs. non-privileged accesses here, so just
204        * use the right address.
205        *
206        * TODO: all uses of MEM_READ_ADDR_HI_PRIVILEGED set bit 31, is this the
207        * right bit or do we need to track writes to it?
208        */
209       if (read_addr_hi & (1u << 31)) {
210          read_addr = (read_addr & 0xffffffff) |
211             ((read_addr_hi & ~(1u << 31)) << 32);
212       }
213 
214       if (read_dwords > 0 && !peek) {
215          emu_set_reg32(emu, &MEM_READ_DWORDS, read_dwords - 1);
216          if (read_addr_hi & (1u << 31)) {
217             /* Privileged memory should all be in the same 4GB space. */
218             emu_set_reg32(emu, &MEM_READ_ADDR, read_addr + 4);
219          } else {
220             emu_set_reg64(emu, &MEM_READ_ADDR, read_addr + 4);
221          }
222       }
223 
224       return emu_mem_read_dword(emu, read_addr);
225    } else if (n == REG_REGDATA) {
226       /* $regdata */
227       EMU_CONTROL_REG(REG_READ_DWORDS);
228       EMU_CONTROL_REG(REG_READ_ADDR);
229 
230       unsigned read_dwords = emu_get_reg32(emu, &REG_READ_DWORDS);
231       unsigned read_addr   = emu_get_reg32(emu, &REG_READ_ADDR);
232 
233       /* I think if the fw doesn't write REG_READ_DWORDS before
234        * REG_READ_ADDR, it just ends up with a single value written
235        * into the FIFO that $regdata is consuming from:
236        */
237       if (read_dwords > 0 && !peek) {
238          emu_set_reg32(emu, &REG_READ_DWORDS, read_dwords - 1);
239          emu_set_reg32(emu, &REG_READ_ADDR,   read_addr + 1);
240       }
241 
242       return emu_get_gpu_reg(emu, read_addr);
243    } else if (n == REG_DATA) {
244       /* $data */
245       if (emu->bootstrap_mode) {
246          emu->bootstrap_finished = true;
247          return 0;
248       }
249 
250       do {
251          uint32_t rem = emu->gpr_regs.val[REG_REM];
252          assert(rem >= 0);
253 
254          uint32_t val;
255          if (peek) {
256             if (emu_queue_peek(&emu->roq, &val))
257                return val;
258          } else {
259             if (emu_queue_pop(&emu->roq, &val)) {
260                emu_set_gpr_reg(emu, REG_REM, --rem);
261                return val;
262             }
263          }
264 
265          /* If FIFO is empty, prompt for more input: */
266          printf("FIFO empty, input a packet!\n");
267          emu->run_mode = false;
268          emu_main_prompt(emu);
269       } while (true);
270    } else {
271       unreachable("not a FIFO reg");
272       return 0;
273    }
274 }
275 
276 static void
emu_set_fifo_reg(struct emu * emu,unsigned n,uint32_t val)277 emu_set_fifo_reg(struct emu *emu, unsigned n, uint32_t val)
278 {
279    if ((n == REG_ADDR) || (n == REG_USRADDR)) {
280       emu->data_mode = (n == REG_ADDR) ? DATA_ADDR : DATA_USRADDR;
281 
282       /* Treat these as normal register writes so we can see
283        * updated values in the output as we step thru the
284        * instructions:
285        */
286       emu->gpr_regs.val[n] = val;
287       BITSET_SET(emu->gpr_regs.written, n);
288 
289       if (is_pipe_reg_addr(val)) {
290          /* "void" pipe regs don't have a value to write, so just
291           * treat it as writing zero to the pipe reg:
292           */
293          if (afuc_pipe_reg_is_void(val >> 24))
294             emu_set_pipe_reg(emu, val >> 24, 0);
295          emu->data_mode = DATA_PIPE;
296       }
297    } else if (n == REG_DATA) {
298       unsigned reg = get_reg_addr(emu);
299       unsigned regoff = emu->gpr_regs.val[reg];
300       if (is_pipe_reg_addr(regoff)) {
301          /* writes pipe registers: */
302 
303          assert(!(regoff & 0xfbffff));
304 
305          /* If b18 is set, don't auto-increment dest addr.. and if we
306           * do auto-increment, we only increment the high 8b
307           *
308           * Note that we bypass emu_set_gpr_reg() in this case because
309           * auto-incrementing isn't triggering a write to "void" pipe
310           * regs.
311           */
312          if (!(regoff & 0x40000)) {
313             emu->gpr_regs.val[reg] = regoff + 0x01000000;
314             BITSET_SET(emu->gpr_regs.written, reg);
315          }
316 
317          emu_set_pipe_reg(emu, regoff >> 24, val);
318       } else {
319          /* writes to gpu registers: */
320          emu_set_gpr_reg(emu, reg, regoff+1);
321          emu_set_gpu_reg(emu, regoff, val);
322       }
323    }
324 }
325 
326 uint32_t
emu_get_gpr_reg_alu(struct emu * emu,unsigned n,bool peek)327 emu_get_gpr_reg_alu(struct emu *emu, unsigned n, bool peek)
328 {
329    assert(n < ARRAY_SIZE(emu->gpr_regs.val));
330 
331    /* Handle special regs: */
332    switch (n) {
333    case 0x00:
334       return 0;
335    case REG_MEMDATA:
336    case REG_REGDATA:
337    case REG_DATA:
338       return emu_get_fifo_reg(emu, n, peek);
339    default:
340       return emu->gpr_regs.val[n];
341    }
342 }
343 
344 uint32_t
emu_get_gpr_reg(struct emu * emu,unsigned n)345 emu_get_gpr_reg(struct emu *emu, unsigned n)
346 {
347    return emu_get_gpr_reg_alu(emu, n, false);
348 }
349 
350 void
emu_set_gpr_reg(struct emu * emu,unsigned n,uint32_t val)351 emu_set_gpr_reg(struct emu *emu, unsigned n, uint32_t val)
352 {
353    assert(n < ARRAY_SIZE(emu->gpr_regs.val));
354 
355    switch (n) {
356    case REG_ADDR:
357    case REG_USRADDR:
358    case REG_DATA:
359       emu_set_fifo_reg(emu, n, val);
360       break;
361    default:
362       emu->gpr_regs.val[n] = val;
363       BITSET_SET(emu->gpr_regs.written, n);
364       break;
365    }
366 }
367 
368 /*
369  * Control/pipe register accessor helpers:
370  */
371 
372 struct emu_reg_accessor {
373    unsigned (*get_offset)(const char *name);
374    uint32_t (*get)(struct emu *emu, unsigned n);
375    void (*set)(struct emu *emu, unsigned n, uint32_t val);
376 };
377 
378 const struct emu_reg_accessor emu_control_accessor = {
379       .get_offset = afuc_control_reg,
380       .get = emu_get_control_reg,
381       .set = emu_set_control_reg,
382 };
383 
384 const struct emu_reg_accessor emu_sqe_accessor = {
385       .get_offset = afuc_sqe_reg,
386       .get = emu_get_sqe_reg,
387       .set = emu_set_sqe_reg,
388 };
389 
390 const struct emu_reg_accessor emu_pipe_accessor = {
391       .get_offset = afuc_pipe_reg,
392       .get = emu_get_pipe_reg,
393       .set = emu_set_pipe_reg,
394 };
395 
396 const struct emu_reg_accessor emu_gpu_accessor = {
397       .get_offset = afuc_gpu_reg,
398       .get = emu_get_gpu_reg,
399       .set = emu_set_gpu_reg,
400 };
401 
402 unsigned
emu_reg_offset(struct emu_reg * reg)403 emu_reg_offset(struct emu_reg *reg)
404 {
405    if (reg->offset == ~0)
406       reg->offset = reg->accessor->get_offset(reg->name);
407    return reg->offset;
408 }
409 
410 uint32_t
emu_get_reg32(struct emu * emu,struct emu_reg * reg)411 emu_get_reg32(struct emu *emu, struct emu_reg *reg)
412 {
413    return reg->accessor->get(emu, emu_reg_offset(reg));
414 }
415 
416 uint64_t
emu_get_reg64(struct emu * emu,struct emu_reg * reg)417 emu_get_reg64(struct emu *emu, struct emu_reg *reg)
418 {
419    uint64_t val = reg->accessor->get(emu, emu_reg_offset(reg) + 1);
420    val <<= 32;
421    val |= reg->accessor->get(emu, emu_reg_offset(reg));
422    return val;
423 }
424 
425 void
emu_set_reg32(struct emu * emu,struct emu_reg * reg,uint32_t val)426 emu_set_reg32(struct emu *emu, struct emu_reg *reg, uint32_t val)
427 {
428    reg->accessor->set(emu, emu_reg_offset(reg), val);
429 }
430 
431 void
emu_set_reg64(struct emu * emu,struct emu_reg * reg,uint64_t val)432 emu_set_reg64(struct emu *emu, struct emu_reg *reg, uint64_t val)
433 {
434    reg->accessor->set(emu, emu_reg_offset(reg),     val);
435    reg->accessor->set(emu, emu_reg_offset(reg) + 1, val >> 32);
436 }
437