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