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