• 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 #define EMU_NUM_GPR_REGS 32
35 
36 struct emu_gpr_regs {
37    BITSET_DECLARE(written, EMU_NUM_GPR_REGS);
38    union {
39       uint32_t pc;
40       uint32_t val[EMU_NUM_GPR_REGS];
41    };
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_GPU_REGS 0x10000
52 
53 struct emu_gpu_regs {
54    BITSET_DECLARE(written, EMU_NUM_GPU_REGS);
55    uint32_t val[EMU_NUM_GPU_REGS];
56 };
57 
58 #define EMU_NUM_PIPE_REGS 0x100
59 
60 struct emu_pipe_regs {
61    BITSET_DECLARE(written, EMU_NUM_PIPE_REGS);
62    uint32_t val[EMU_NUM_PIPE_REGS];
63 };
64 
65 /**
66  * A simple queue implementation to buffer up cmdstream for the
67  * emulated firmware to consume
68  */
69 struct emu_queue {
70    unsigned head, tail, count;
71    uint32_t fifo[0x100];
72 };
73 
74 static inline bool
emu_queue_push(struct emu_queue * q,uint32_t val)75 emu_queue_push(struct emu_queue *q, uint32_t val)
76 {
77    if (q->count >= ARRAY_SIZE(q->fifo))
78       return false;
79 
80    q->count++;
81    q->head++;
82    q->head %= ARRAY_SIZE(q->fifo);
83 
84    q->fifo[q->head] = val;
85 
86    return true;
87 }
88 
89 static inline bool
emu_queue_pop(struct emu_queue * q,uint32_t * val)90 emu_queue_pop(struct emu_queue *q, uint32_t *val)
91 {
92    if (!q->count)
93       return false;
94 
95    q->count--;
96    q->tail++;
97    q->tail %= ARRAY_SIZE(q->fifo);
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    unsigned write_idx;
110    struct {
111       union {
112          uint32_t hdr;
113          struct {
114             uint16_t count;       /* # of dwords */
115             uint16_t mode_mask;
116          };
117       };
118       union {
119          uint32_t base_lohi[2];
120          uint64_t base;
121       };
122       uint64_t sds_base;
123       uint32_t sds_dwords;
124    } state[32];
125 };
126 
127 /**
128  * The GPU memory size:
129  *
130  * The size is a bit arbitrary, and could be increased.  The backing
131  * storage is a MAP_ANONYMOUS mapping so untouched pages should not
132  * have a cost other than consuming virtual address space.
133  *
134  * Use something >4gb so we can test that anything doing GPU pointer
135  * math correctly handles rollover
136  */
137 #define EMU_MEMORY_SIZE 0x200000000
138 
139 /**
140  * The GPU "address" of the instructions themselves:
141  *
142  * Note address is kind of arbitrary, but should be something non-
143  * zero to sanity check the bootstrap process and packet-table
144  * loading
145  */
146 #define EMU_INSTR_BASE 0x1000
147 
148 /**
149  * Emulated hw state.
150  */
151 struct emu {
152    /**
153     * In bootstrap mode, execute bootstrap without outputting anything.
154     * Useful to (for example) extract packet-table.
155     */
156    bool quiet;
157 
158    bool lpac;
159 
160    uint32_t *instrs;
161    unsigned sizedwords;
162    unsigned gpu_id;
163 
164    struct emu_control_regs control_regs;
165    struct emu_pipe_regs    pipe_regs;
166    struct emu_gpu_regs     gpu_regs;
167    struct emu_gpr_regs     gpr_regs;
168 
169    struct emu_draw_state   draw_state;
170 
171    /* branch target to jump to after next instruction (ie. after delay-
172     * slot):
173     */
174    uint32_t branch_target;
175 
176    /* executed waitin, jump to handler after next instruction (ie. after
177     * delay-slot):
178     */
179    bool waitin;
180 
181    /* (r)un mode, don't stop for input until next waitin: */
182    bool run_mode;
183 
184    /* carry-bits for add/sub for addhi/subhi */
185    uint32_t carry;
186 
187    /* call-stack of saved PCs.. I expect this to be a fixed size, but not
188     * sure what the actual size is
189     */
190    uint32_t call_stack[5];
191    int call_stack_idx;
192 
193    /* packet table (aka jmptable) has offsets for pm4 packet handlers: */
194    uint32_t jmptbl[0x80];
195 
196    /* In reality ROQ is actually multiple queues, but we don't try
197     * to model the hw that exactly (but instead only model the behavior)
198     * so we just use this to buffer up cmdstream input
199     */
200    struct emu_queue roq;
201 
202    /* Mode for writes to $data: */
203    enum {
204       DATA_ADDR,
205       DATA_USRADDR,
206       DATA_PIPE,
207    } data_mode;
208 
209    /* GPU address space: */
210    void *gpumem;
211 
212    /* A bitset would be prohibitively large to track memory writes, to
213     * show in the state-change dump.  But we can only write a single
214     * dword per instruction (given that for (rep) and/or (xmov) we
215     * dump state change at each "step" of the instruction.
216     *
217     * ~0 means no memory write
218     */
219    uintptr_t gpumem_written;
220 };
221 
222 /*
223  * API for disasm to use:
224  */
225 void emu_step(struct emu *emu);
226 void emu_run_bootstrap(struct emu *emu);
227 void emu_init(struct emu *emu);
228 void emu_fini(struct emu *emu);
229 
230 /*
231  * Internal APIs
232  */
233 
234 uint32_t emu_mem_read_dword(struct emu *emu, uintptr_t gpuaddr);
235 void emu_mem_write_dword(struct emu *emu, uintptr_t gpuaddr, uint32_t val);
236 
237 /* UI: */
238 void emu_main_prompt(struct emu *emu);
239 void emu_clear_state_change(struct emu *emu);
240 void emu_dump_state_change(struct emu *emu);
241 
242 /* Registers: */
243 uint32_t emu_get_gpr_reg(struct emu *emu, unsigned n);
244 void emu_set_gpr_reg(struct emu *emu, unsigned n, uint32_t val);
245 
246 void emu_set_gpu_reg(struct emu *emu, unsigned n, uint32_t val);
247 
248 uint32_t emu_get_control_reg(struct emu *emu, unsigned n);
249 void emu_set_control_reg(struct emu *emu, unsigned n, uint32_t val);
250 
251 /* Register helpers for fixed fxn emulation, to avoid lots of boilerplate
252  * for accessing other pipe/control registers.
253  *
254  * Example:
255  *    EMU_CONTROL_REG(REG_NAME);
256  *    val = emu_get_reg32(emu, &SOME_REG);
257  */
258 
259 struct emu_reg_accessor;
260 
261 struct emu_reg {
262    const char *name;
263    const struct emu_reg_accessor *accessor;
264    unsigned offset;
265 };
266 
267 extern const struct emu_reg_accessor emu_control_accessor;
268 extern const struct emu_reg_accessor emu_pipe_accessor;
269 extern const struct emu_reg_accessor emu_gpu_accessor;
270 
271 #define EMU_CONTROL_REG(name) static struct emu_reg name = { #name, &emu_control_accessor, ~0 }
272 #define EMU_PIPE_REG(name)    static struct emu_reg name = { #name, &emu_pipe_accessor, ~0 }
273 #define EMU_GPU_REG(name)     static struct emu_reg name = { #name, &emu_gpu_accessor, ~0 }
274 
275 unsigned emu_reg_offset(struct emu_reg *reg);
276 uint32_t emu_get_reg32(struct emu *emu, struct emu_reg *reg);
277 uint64_t emu_get_reg64(struct emu *emu, struct emu_reg *reg);
278 void emu_set_reg32(struct emu *emu, struct emu_reg *reg, uint32_t val);
279 void emu_set_reg64(struct emu *emu, struct emu_reg *reg, uint64_t val);
280 
281 /* Draw-state control reg emulation: */
282 uint32_t emu_get_draw_state_reg(struct emu *emu, unsigned n);
283 void emu_set_draw_state_reg(struct emu *emu, unsigned n, uint32_t val);
284 
285 /* Helpers: */
286 #define printdelta(fmt, ...) afuc_printc(AFUC_ERR, fmt, ##__VA_ARGS__)
287 
288 #endif /* _ASM_H_ */
289