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