xref: /aosp_15_r20/external/mesa3d/src/freedreno/afuc/emu.h (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright © 2021 Google, Inc.
3  * SPDX-License-Identifier: MIT
4  */
5 
6 #ifndef _EMU_H_
7 #define _EMU_H_
8 
9 #include <stdbool.h>
10 #include <stdint.h>
11 
12 #include "util/bitset.h"
13 
14 #include "afuc.h"
15 
16 extern int gpuver;
17 
18 #define EMU_NUM_GPR_REGS 32
19 
20 struct emu_gpr_regs {
21    BITSET_DECLARE(written, EMU_NUM_GPR_REGS);
22    uint32_t pc;
23    uint32_t val[EMU_NUM_GPR_REGS];
24 };
25 
26 #define EMU_NUM_CONTROL_REGS 0x1000
27 
28 struct emu_control_regs {
29    BITSET_DECLARE(written, EMU_NUM_CONTROL_REGS);
30    uint32_t val[EMU_NUM_CONTROL_REGS];
31 };
32 
33 #define EMU_NUM_SQE_REGS 0x10
34 
35 struct emu_sqe_regs {
36    BITSET_DECLARE(written, EMU_NUM_SQE_REGS);
37    uint32_t val[EMU_NUM_SQE_REGS];
38 };
39 
40 #define EMU_NUM_GPU_REGS 0x10000
41 
42 struct emu_gpu_regs {
43    BITSET_DECLARE(written, EMU_NUM_GPU_REGS);
44    uint32_t val[EMU_NUM_GPU_REGS];
45 };
46 
47 #define EMU_NUM_PIPE_REGS 0x100
48 
49 struct emu_pipe_regs {
50    BITSET_DECLARE(written, EMU_NUM_PIPE_REGS);
51    uint32_t val[EMU_NUM_PIPE_REGS];
52 };
53 
54 /**
55  * A simple queue implementation to buffer up cmdstream for the
56  * emulated firmware to consume
57  */
58 struct emu_queue {
59    unsigned head, tail, count;
60    uint32_t fifo[0x100];
61 };
62 
63 static inline bool
emu_queue_push(struct emu_queue * q,uint32_t val)64 emu_queue_push(struct emu_queue *q, uint32_t val)
65 {
66    if (q->count >= ARRAY_SIZE(q->fifo))
67       return false;
68 
69    q->count++;
70    q->head++;
71    q->head %= ARRAY_SIZE(q->fifo);
72 
73    q->fifo[q->head] = val;
74 
75    return true;
76 }
77 
78 static inline bool
emu_queue_pop(struct emu_queue * q,uint32_t * val)79 emu_queue_pop(struct emu_queue *q, uint32_t *val)
80 {
81    if (!q->count)
82       return false;
83 
84    q->count--;
85    q->tail++;
86    q->tail %= ARRAY_SIZE(q->fifo);
87 
88    *val = q->fifo[q->tail];
89 
90    return true;
91 }
92 
93 static inline bool
emu_queue_peek(struct emu_queue * q,uint32_t * val)94 emu_queue_peek(struct emu_queue *q, uint32_t *val)
95 {
96    if (!q->count)
97       return false;
98 
99    *val = q->fifo[q->tail];
100 
101    return true;
102 }
103 
104 /**
105  * Draw-state (ie. CP_SET_DRAW_STATE) related emulation
106  */
107 struct emu_draw_state {
108    unsigned prev_draw_state_sel;
109    struct {
110       union {
111          uint32_t hdr;
112          struct {
113             uint16_t count;       /* # of dwords */
114             uint16_t mode_mask;
115          };
116       };
117       union {
118          uint32_t base_lohi[2];
119          uint64_t base;
120       };
121       uint64_t sds_base;
122       uint32_t sds_dwords;
123    } state[32];
124 };
125 
126 /**
127  * The GPU memory size:
128  *
129  * The size is a bit arbitrary, and could be increased.  The backing
130  * storage is a MAP_ANONYMOUS mapping so untouched pages should not
131  * have a cost other than consuming virtual address space.
132  *
133  * Use something >4gb so we can test that anything doing GPU pointer
134  * math correctly handles rollover
135  */
136 #define EMU_MEMORY_SIZE 0x200000000
137 
138 /**
139  * The GPU "address" of the instructions themselves:
140  *
141  * Note address is kind of arbitrary, but should be something non-
142  * zero to sanity check the bootstrap process and packet-table
143  * loading
144  */
145 #define EMU_INSTR_BASE 0x1000
146 
147 /**
148  * Emulated hw state.
149  */
150 struct emu {
151    /**
152     * In bootstrap mode, execute bootstrap without outputting anything.
153     * Useful to (for example) extract packet-table.
154     */
155    bool quiet;
156 
157    enum {
158       EMU_PROC_SQE,
159       EMU_PROC_BV,
160       EMU_PROC_LPAC,
161    } processor;
162 
163    uint32_t *instrs;
164    unsigned sizedwords;
165    unsigned fw_id;
166 
167    struct emu_control_regs control_regs;
168    struct emu_sqe_regs     sqe_regs;
169    struct emu_pipe_regs    pipe_regs;
170    struct emu_gpu_regs     gpu_regs;
171    struct emu_gpr_regs     gpr_regs;
172 
173    struct emu_draw_state   draw_state;
174 
175    /* branch target to jump to after next instruction (ie. after delay-
176     * slot):
177     */
178    uint32_t branch_target;
179 
180    /* executed waitin, jump to handler after next instruction (ie. after
181     * delay-slot):
182     */
183    bool waitin;
184 
185    /* (r)un mode, don't stop for input until next waitin: */
186    bool run_mode;
187 
188    /* Don't prompt on a read from $data with an empty queue and instead assume
189     * the bootstrap routine has finished and return a dummy value while
190     * setting bootstrap_finished.
191     */
192    bool bootstrap_mode;
193 
194    bool bootstrap_finished;
195 
196    /* carry-bits for add/sub for addhi/subhi
197     * TODO: this is probably in a SQE register somewhere
198     */
199    uint32_t carry;
200 
201    /* packet table (aka jmptable) has offsets for pm4 packet handlers: */
202    uint32_t jmptbl[0x80];
203 
204    /* In reality ROQ is actually multiple queues, but we don't try
205     * to model the hw that exactly (but instead only model the behavior)
206     * so we just use this to buffer up cmdstream input
207     */
208    struct emu_queue roq;
209 
210    /* Mode for writes to $data: */
211    enum {
212       DATA_ADDR,
213       DATA_USRADDR,
214       DATA_PIPE,
215    } data_mode;
216 
217    /* GPU address space: */
218    void *gpumem;
219 
220    /* A bitset would be prohibitively large to track memory writes, to
221     * show in the state-change dump.  But we can only write a single
222     * dword per instruction (given that for (rep) and/or (xmov) we
223     * dump state change at each "step" of the instruction.
224     *
225     * ~0 means no memory write
226     */
227    uintptr_t gpumem_written;
228 };
229 
230 /*
231  * API for disasm to use:
232  */
233 void emu_step(struct emu *emu);
234 void emu_run_bootstrap(struct emu *emu);
235 void emu_init(struct emu *emu);
236 void emu_fini(struct emu *emu);
237 
238 /*
239  * Internal APIs
240  */
241 
242 uint32_t emu_mem_read_dword(struct emu *emu, uintptr_t gpuaddr);
243 void emu_mem_write_dword(struct emu *emu, uintptr_t gpuaddr, uint32_t val);
244 
245 /* UI: */
246 void emu_main_prompt(struct emu *emu);
247 void emu_clear_state_change(struct emu *emu);
248 void emu_dump_state_change(struct emu *emu);
249 
250 /* Registers: */
251 uint32_t emu_get_gpr_reg(struct emu *emu, unsigned n);
252 void emu_set_gpr_reg(struct emu *emu, unsigned n, uint32_t val);
253 uint32_t emu_get_gpr_reg_alu(struct emu *emu, unsigned n, bool peek);
254 
255 void emu_set_gpu_reg(struct emu *emu, unsigned n, uint32_t val);
256 
257 uint32_t emu_get_control_reg(struct emu *emu, unsigned n);
258 void emu_set_control_reg(struct emu *emu, unsigned n, uint32_t val);
259 
260 uint32_t emu_get_sqe_reg(struct emu *emu, unsigned n);
261 void emu_set_sqe_reg(struct emu *emu, unsigned n, uint32_t val);
262 
263 /* Register helpers for fixed fxn emulation, to avoid lots of boilerplate
264  * for accessing other pipe/control registers.
265  *
266  * Example:
267  *    EMU_CONTROL_REG(REG_NAME);
268  *    val = emu_get_reg32(emu, &SOME_REG);
269  */
270 
271 struct emu_reg_accessor;
272 
273 struct emu_reg {
274    const char *name;
275    const struct emu_reg_accessor *accessor;
276    unsigned offset;
277 };
278 
279 extern const struct emu_reg_accessor emu_control_accessor;
280 extern const struct emu_reg_accessor emu_sqe_accessor;
281 extern const struct emu_reg_accessor emu_pipe_accessor;
282 extern const struct emu_reg_accessor emu_gpu_accessor;
283 
284 #define EMU_CONTROL_REG(name) static struct emu_reg name = { #name, &emu_control_accessor, ~0 }
285 #define EMU_SQE_REG(name) static struct emu_reg name = { #name, &emu_sqe_accessor, ~0 }
286 #define EMU_PIPE_REG(name)    static struct emu_reg name = { #name, &emu_pipe_accessor, ~0 }
287 #define EMU_GPU_REG(name)     static struct emu_reg name = { #name, &emu_gpu_accessor, ~0 }
288 
289 unsigned emu_reg_offset(struct emu_reg *reg);
290 uint32_t emu_get_reg32(struct emu *emu, struct emu_reg *reg);
291 uint64_t emu_get_reg64(struct emu *emu, struct emu_reg *reg);
292 void emu_set_reg32(struct emu *emu, struct emu_reg *reg, uint32_t val);
293 void emu_set_reg64(struct emu *emu, struct emu_reg *reg, uint64_t val);
294 
295 /* Draw-state control reg emulation: */
296 uint32_t emu_get_draw_state_reg(struct emu *emu, unsigned n);
297 void emu_set_draw_state_reg(struct emu *emu, unsigned n, uint32_t val);
298 void emu_set_draw_state_base(struct emu *emu, unsigned n, uint32_t val);
299 
300 /* Helpers: */
301 #define printdelta(fmt, ...) afuc_printc(AFUC_ERR, fmt, ##__VA_ARGS__)
302 
303 #endif /* _ASM_H_ */
304