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(®_WRITE)) {
64 uint32_t write_addr = emu_get_reg32(emu, ®_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, ®_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, ®_READ_DWORDS);
231 unsigned read_addr = emu_get_reg32(emu, ®_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, ®_READ_DWORDS, read_dwords - 1);
239 emu_set_reg32(emu, ®_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