17ec681f3Smrg/* 27ec681f3Smrg * Copyright © 2021 Google, Inc. 37ec681f3Smrg * 47ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a 57ec681f3Smrg * copy of this software and associated documentation files (the "Software"), 67ec681f3Smrg * to deal in the Software without restriction, including without limitation 77ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 87ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the 97ec681f3Smrg * Software is furnished to do so, subject to the following conditions: 107ec681f3Smrg * 117ec681f3Smrg * The above copyright notice and this permission notice (including the next 127ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the 137ec681f3Smrg * Software. 147ec681f3Smrg * 157ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 167ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 177ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 187ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 197ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 207ec681f3Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 217ec681f3Smrg * SOFTWARE. 227ec681f3Smrg */ 237ec681f3Smrg 247ec681f3Smrg#include <assert.h> 257ec681f3Smrg#include <ctype.h> 267ec681f3Smrg#include <stdio.h> 277ec681f3Smrg#include <stdlib.h> 287ec681f3Smrg 297ec681f3Smrg#include "emu.h" 307ec681f3Smrg#include "util.h" 317ec681f3Smrg 327ec681f3Smrg/* 337ec681f3Smrg * Emulator Registers: 347ec681f3Smrg * 357ec681f3Smrg * Handles access to GPR, GPU, control, and pipe registers. 367ec681f3Smrg */ 377ec681f3Smrg 387ec681f3Smrgstatic bool 397ec681f3Smrgis_draw_state_control_reg(unsigned n) 407ec681f3Smrg{ 417ec681f3Smrg char *reg_name = afuc_control_reg_name(n); 427ec681f3Smrg if (!reg_name) 437ec681f3Smrg return false; 447ec681f3Smrg bool ret = !!strstr(reg_name, "DRAW_STATE"); 457ec681f3Smrg free(reg_name); 467ec681f3Smrg return ret; 477ec681f3Smrg} 487ec681f3Smrg 497ec681f3Smrguint32_t 507ec681f3Smrgemu_get_control_reg(struct emu *emu, unsigned n) 517ec681f3Smrg{ 527ec681f3Smrg assert(n < ARRAY_SIZE(emu->control_regs.val)); 537ec681f3Smrg if (is_draw_state_control_reg(n)) 547ec681f3Smrg return emu_get_draw_state_reg(emu, n); 557ec681f3Smrg return emu->control_regs.val[n]; 567ec681f3Smrg} 577ec681f3Smrg 587ec681f3Smrgvoid 597ec681f3Smrgemu_set_control_reg(struct emu *emu, unsigned n, uint32_t val) 607ec681f3Smrg{ 617ec681f3Smrg EMU_CONTROL_REG(PACKET_TABLE_WRITE); 627ec681f3Smrg EMU_CONTROL_REG(PACKET_TABLE_WRITE_ADDR); 637ec681f3Smrg EMU_CONTROL_REG(REG_WRITE); 647ec681f3Smrg EMU_CONTROL_REG(REG_WRITE_ADDR); 657ec681f3Smrg 667ec681f3Smrg assert(n < ARRAY_SIZE(emu->control_regs.val)); 677ec681f3Smrg BITSET_SET(emu->control_regs.written, n); 687ec681f3Smrg emu->control_regs.val[n] = val; 697ec681f3Smrg 707ec681f3Smrg /* Some control regs have special action on write: */ 717ec681f3Smrg if (n == emu_reg_offset(&PACKET_TABLE_WRITE)) { 727ec681f3Smrg unsigned write_addr = emu_get_reg32(emu, &PACKET_TABLE_WRITE_ADDR); 737ec681f3Smrg 747ec681f3Smrg assert(write_addr < ARRAY_SIZE(emu->jmptbl)); 757ec681f3Smrg emu->jmptbl[write_addr] = val; 767ec681f3Smrg 777ec681f3Smrg emu_set_reg32(emu, &PACKET_TABLE_WRITE_ADDR, write_addr + 1); 787ec681f3Smrg } else if (n == emu_reg_offset(®_WRITE)) { 797ec681f3Smrg uint32_t write_addr = emu_get_reg32(emu, ®_WRITE_ADDR); 807ec681f3Smrg 817ec681f3Smrg /* Upper bits seem like some flags, not part of the actual 827ec681f3Smrg * register offset.. not sure what they mean yet: 837ec681f3Smrg */ 847ec681f3Smrg uint32_t flags = write_addr >> 16; 857ec681f3Smrg write_addr &= 0xffff; 867ec681f3Smrg 877ec681f3Smrg emu_set_gpu_reg(emu, write_addr++, val); 887ec681f3Smrg emu_set_reg32(emu, ®_WRITE_ADDR, write_addr | (flags << 16)); 897ec681f3Smrg } else if (is_draw_state_control_reg(n)) { 907ec681f3Smrg emu_set_draw_state_reg(emu, n, val); 917ec681f3Smrg } 927ec681f3Smrg} 937ec681f3Smrg 947ec681f3Smrgstatic uint32_t 957ec681f3Smrgemu_get_pipe_reg(struct emu *emu, unsigned n) 967ec681f3Smrg{ 977ec681f3Smrg assert(n < ARRAY_SIZE(emu->pipe_regs.val)); 987ec681f3Smrg return emu->pipe_regs.val[n]; 997ec681f3Smrg} 1007ec681f3Smrg 1017ec681f3Smrgstatic void 1027ec681f3Smrgemu_set_pipe_reg(struct emu *emu, unsigned n, uint32_t val) 1037ec681f3Smrg{ 1047ec681f3Smrg EMU_PIPE_REG(NRT_DATA); 1057ec681f3Smrg EMU_PIPE_REG(NRT_ADDR); 1067ec681f3Smrg 1077ec681f3Smrg assert(n < ARRAY_SIZE(emu->pipe_regs.val)); 1087ec681f3Smrg BITSET_SET(emu->pipe_regs.written, n); 1097ec681f3Smrg emu->pipe_regs.val[n] = val; 1107ec681f3Smrg 1117ec681f3Smrg /* Some pipe regs have special action on write: */ 1127ec681f3Smrg if (n == emu_reg_offset(&NRT_DATA)) { 1137ec681f3Smrg uintptr_t addr = emu_get_reg64(emu, &NRT_ADDR); 1147ec681f3Smrg 1157ec681f3Smrg emu_mem_write_dword(emu, addr, val); 1167ec681f3Smrg 1177ec681f3Smrg emu_set_reg64(emu, &NRT_ADDR, addr + 4); 1187ec681f3Smrg } 1197ec681f3Smrg} 1207ec681f3Smrg 1217ec681f3Smrgstatic uint32_t 1227ec681f3Smrgemu_get_gpu_reg(struct emu *emu, unsigned n) 1237ec681f3Smrg{ 1247ec681f3Smrg if (n >= ARRAY_SIZE(emu->gpu_regs.val)) 1257ec681f3Smrg return 0; 1267ec681f3Smrg assert(n < ARRAY_SIZE(emu->gpu_regs.val)); 1277ec681f3Smrg return emu->gpu_regs.val[n]; 1287ec681f3Smrg} 1297ec681f3Smrg 1307ec681f3Smrgvoid 1317ec681f3Smrgemu_set_gpu_reg(struct emu *emu, unsigned n, uint32_t val) 1327ec681f3Smrg{ 1337ec681f3Smrg if (n >= ARRAY_SIZE(emu->gpu_regs.val)) 1347ec681f3Smrg return; 1357ec681f3Smrg assert(n < ARRAY_SIZE(emu->gpu_regs.val)); 1367ec681f3Smrg BITSET_SET(emu->gpu_regs.written, n); 1377ec681f3Smrg emu->gpu_regs.val[n] = val; 1387ec681f3Smrg} 1397ec681f3Smrg 1407ec681f3Smrgstatic bool 1417ec681f3Smrgis_pipe_reg_addr(unsigned regoff) 1427ec681f3Smrg{ 1437ec681f3Smrg return regoff > 0xffff; 1447ec681f3Smrg} 1457ec681f3Smrg 1467ec681f3Smrgstatic unsigned 1477ec681f3Smrgget_reg_addr(struct emu *emu) 1487ec681f3Smrg{ 1497ec681f3Smrg switch (emu->data_mode) { 1507ec681f3Smrg case DATA_PIPE: 1517ec681f3Smrg case DATA_ADDR: return REG_ADDR; 1527ec681f3Smrg case DATA_USRADDR: return REG_USRADDR; 1537ec681f3Smrg default: 1547ec681f3Smrg unreachable("bad data_mode"); 1557ec681f3Smrg return 0; 1567ec681f3Smrg } 1577ec681f3Smrg} 1587ec681f3Smrg 1597ec681f3Smrg/* Handle reads for special streaming regs: */ 1607ec681f3Smrgstatic uint32_t 1617ec681f3Smrgemu_get_fifo_reg(struct emu *emu, unsigned n) 1627ec681f3Smrg{ 1637ec681f3Smrg /* TODO the fifo regs are slurping out of a FIFO that the hw is filling 1647ec681f3Smrg * in parallel.. we can use `struct emu_queue` to emulate what is actually 1657ec681f3Smrg * happening more accurately 1667ec681f3Smrg */ 1677ec681f3Smrg 1687ec681f3Smrg if (n == REG_MEMDATA) { 1697ec681f3Smrg /* $memdata */ 1707ec681f3Smrg EMU_CONTROL_REG(MEM_READ_DWORDS); 1717ec681f3Smrg EMU_CONTROL_REG(MEM_READ_ADDR); 1727ec681f3Smrg 1737ec681f3Smrg unsigned read_dwords = emu_get_reg32(emu, &MEM_READ_DWORDS); 1747ec681f3Smrg uintptr_t read_addr = emu_get_reg64(emu, &MEM_READ_ADDR); 1757ec681f3Smrg 1767ec681f3Smrg if (read_dwords > 0) { 1777ec681f3Smrg emu_set_reg32(emu, &MEM_READ_DWORDS, read_dwords - 1); 1787ec681f3Smrg emu_set_reg64(emu, &MEM_READ_ADDR, read_addr + 4); 1797ec681f3Smrg } 1807ec681f3Smrg 1817ec681f3Smrg return emu_mem_read_dword(emu, read_addr); 1827ec681f3Smrg } else if (n == REG_REGDATA) { 1837ec681f3Smrg /* $regdata */ 1847ec681f3Smrg EMU_CONTROL_REG(REG_READ_DWORDS); 1857ec681f3Smrg EMU_CONTROL_REG(REG_READ_ADDR); 1867ec681f3Smrg 1877ec681f3Smrg unsigned read_dwords = emu_get_reg32(emu, ®_READ_DWORDS); 1887ec681f3Smrg unsigned read_addr = emu_get_reg32(emu, ®_READ_ADDR); 1897ec681f3Smrg 1907ec681f3Smrg /* I think if the fw doesn't write REG_READ_DWORDS before 1917ec681f3Smrg * REG_READ_ADDR, it just ends up with a single value written 1927ec681f3Smrg * into the FIFO that $regdata is consuming from: 1937ec681f3Smrg */ 1947ec681f3Smrg if (read_dwords > 0) { 1957ec681f3Smrg emu_set_reg32(emu, ®_READ_DWORDS, read_dwords - 1); 1967ec681f3Smrg emu_set_reg32(emu, ®_READ_ADDR, read_addr + 1); 1977ec681f3Smrg } 1987ec681f3Smrg 1997ec681f3Smrg return emu_get_gpu_reg(emu, read_addr); 2007ec681f3Smrg } else if (n == REG_DATA) { 2017ec681f3Smrg /* $data */ 2027ec681f3Smrg do { 2037ec681f3Smrg uint32_t rem = emu->gpr_regs.val[REG_REM]; 2047ec681f3Smrg assert(rem >= 0); 2057ec681f3Smrg 2067ec681f3Smrg uint32_t val; 2077ec681f3Smrg if (emu_queue_pop(&emu->roq, &val)) { 2087ec681f3Smrg emu_set_gpr_reg(emu, REG_REM, --rem); 2097ec681f3Smrg return val; 2107ec681f3Smrg } 2117ec681f3Smrg 2127ec681f3Smrg /* If FIFO is empty, prompt for more input: */ 2137ec681f3Smrg printf("FIFO empty, input a packet!\n"); 2147ec681f3Smrg emu->run_mode = false; 2157ec681f3Smrg emu_main_prompt(emu); 2167ec681f3Smrg } while (true); 2177ec681f3Smrg } else { 2187ec681f3Smrg unreachable("not a FIFO reg"); 2197ec681f3Smrg return 0; 2207ec681f3Smrg } 2217ec681f3Smrg} 2227ec681f3Smrg 2237ec681f3Smrgstatic void 2247ec681f3Smrgemu_set_fifo_reg(struct emu *emu, unsigned n, uint32_t val) 2257ec681f3Smrg{ 2267ec681f3Smrg if ((n == REG_ADDR) || (n == REG_USRADDR)) { 2277ec681f3Smrg emu->data_mode = (n == REG_ADDR) ? DATA_ADDR : DATA_USRADDR; 2287ec681f3Smrg 2297ec681f3Smrg /* Treat these as normal register writes so we can see 2307ec681f3Smrg * updated values in the output as we step thru the 2317ec681f3Smrg * instructions: 2327ec681f3Smrg */ 2337ec681f3Smrg emu->gpr_regs.val[n] = val; 2347ec681f3Smrg BITSET_SET(emu->gpr_regs.written, n); 2357ec681f3Smrg 2367ec681f3Smrg if (is_pipe_reg_addr(val)) { 2377ec681f3Smrg /* "void" pipe regs don't have a value to write, so just 2387ec681f3Smrg * treat it as writing zero to the pipe reg: 2397ec681f3Smrg */ 2407ec681f3Smrg if (afuc_pipe_reg_is_void(val >> 24)) 2417ec681f3Smrg emu_set_pipe_reg(emu, val >> 24, 0); 2427ec681f3Smrg emu->data_mode = DATA_PIPE; 2437ec681f3Smrg } 2447ec681f3Smrg } else if (n == REG_DATA) { 2457ec681f3Smrg unsigned reg = get_reg_addr(emu); 2467ec681f3Smrg unsigned regoff = emu->gpr_regs.val[reg]; 2477ec681f3Smrg if (is_pipe_reg_addr(regoff)) { 2487ec681f3Smrg /* writes pipe registers: */ 2497ec681f3Smrg 2507ec681f3Smrg assert(!(regoff & 0xfbffff)); 2517ec681f3Smrg 2527ec681f3Smrg /* If b18 is set, don't auto-increment dest addr.. and if we 2537ec681f3Smrg * do auto-increment, we only increment the high 8b 2547ec681f3Smrg * 2557ec681f3Smrg * Note that we bypass emu_set_gpr_reg() in this case because 2567ec681f3Smrg * auto-incrementing isn't triggering a write to "void" pipe 2577ec681f3Smrg * regs. 2587ec681f3Smrg */ 2597ec681f3Smrg if (!(regoff & 0x40000)) { 2607ec681f3Smrg emu->gpr_regs.val[reg] = regoff + 0x01000000; 2617ec681f3Smrg BITSET_SET(emu->gpr_regs.written, reg); 2627ec681f3Smrg } 2637ec681f3Smrg 2647ec681f3Smrg emu_set_pipe_reg(emu, regoff >> 24, val); 2657ec681f3Smrg } else { 2667ec681f3Smrg /* writes to gpu registers: */ 2677ec681f3Smrg emu_set_gpr_reg(emu, reg, regoff+1); 2687ec681f3Smrg emu_set_gpu_reg(emu, regoff, val); 2697ec681f3Smrg } 2707ec681f3Smrg } 2717ec681f3Smrg} 2727ec681f3Smrg 2737ec681f3Smrguint32_t 2747ec681f3Smrgemu_get_gpr_reg(struct emu *emu, unsigned n) 2757ec681f3Smrg{ 2767ec681f3Smrg assert(n < ARRAY_SIZE(emu->gpr_regs.val)); 2777ec681f3Smrg 2787ec681f3Smrg /* Handle special regs: */ 2797ec681f3Smrg switch (n) { 2807ec681f3Smrg case 0x00: 2817ec681f3Smrg return 0; 2827ec681f3Smrg case REG_MEMDATA: 2837ec681f3Smrg case REG_REGDATA: 2847ec681f3Smrg case REG_DATA: 2857ec681f3Smrg return emu_get_fifo_reg(emu, n); 2867ec681f3Smrg default: 2877ec681f3Smrg return emu->gpr_regs.val[n]; 2887ec681f3Smrg } 2897ec681f3Smrg} 2907ec681f3Smrg 2917ec681f3Smrgvoid 2927ec681f3Smrgemu_set_gpr_reg(struct emu *emu, unsigned n, uint32_t val) 2937ec681f3Smrg{ 2947ec681f3Smrg assert(n < ARRAY_SIZE(emu->gpr_regs.val)); 2957ec681f3Smrg 2967ec681f3Smrg switch (n) { 2977ec681f3Smrg case REG_ADDR: 2987ec681f3Smrg case REG_USRADDR: 2997ec681f3Smrg case REG_DATA: 3007ec681f3Smrg emu_set_fifo_reg(emu, n, val); 3017ec681f3Smrg break; 3027ec681f3Smrg default: 3037ec681f3Smrg emu->gpr_regs.val[n] = val; 3047ec681f3Smrg BITSET_SET(emu->gpr_regs.written, n); 3057ec681f3Smrg break; 3067ec681f3Smrg } 3077ec681f3Smrg} 3087ec681f3Smrg 3097ec681f3Smrg/* 3107ec681f3Smrg * Control/pipe register accessor helpers: 3117ec681f3Smrg */ 3127ec681f3Smrg 3137ec681f3Smrgstruct emu_reg_accessor { 3147ec681f3Smrg unsigned (*get_offset)(const char *name); 3157ec681f3Smrg uint32_t (*get)(struct emu *emu, unsigned n); 3167ec681f3Smrg void (*set)(struct emu *emu, unsigned n, uint32_t val); 3177ec681f3Smrg}; 3187ec681f3Smrg 3197ec681f3Smrgconst struct emu_reg_accessor emu_control_accessor = { 3207ec681f3Smrg .get_offset = afuc_control_reg, 3217ec681f3Smrg .get = emu_get_control_reg, 3227ec681f3Smrg .set = emu_set_control_reg, 3237ec681f3Smrg}; 3247ec681f3Smrg 3257ec681f3Smrgconst struct emu_reg_accessor emu_pipe_accessor = { 3267ec681f3Smrg .get_offset = afuc_pipe_reg, 3277ec681f3Smrg .get = emu_get_pipe_reg, 3287ec681f3Smrg .set = emu_set_pipe_reg, 3297ec681f3Smrg}; 3307ec681f3Smrg 3317ec681f3Smrgconst struct emu_reg_accessor emu_gpu_accessor = { 3327ec681f3Smrg .get_offset = afuc_gpu_reg, 3337ec681f3Smrg .get = emu_get_gpu_reg, 3347ec681f3Smrg .set = emu_set_gpu_reg, 3357ec681f3Smrg}; 3367ec681f3Smrg 3377ec681f3Smrgunsigned 3387ec681f3Smrgemu_reg_offset(struct emu_reg *reg) 3397ec681f3Smrg{ 3407ec681f3Smrg if (reg->offset == ~0) 3417ec681f3Smrg reg->offset = reg->accessor->get_offset(reg->name); 3427ec681f3Smrg return reg->offset; 3437ec681f3Smrg} 3447ec681f3Smrg 3457ec681f3Smrguint32_t 3467ec681f3Smrgemu_get_reg32(struct emu *emu, struct emu_reg *reg) 3477ec681f3Smrg{ 3487ec681f3Smrg return reg->accessor->get(emu, emu_reg_offset(reg)); 3497ec681f3Smrg} 3507ec681f3Smrg 3517ec681f3Smrguint64_t 3527ec681f3Smrgemu_get_reg64(struct emu *emu, struct emu_reg *reg) 3537ec681f3Smrg{ 3547ec681f3Smrg uint64_t val = reg->accessor->get(emu, emu_reg_offset(reg) + 1); 3557ec681f3Smrg val <<= 32; 3567ec681f3Smrg val |= reg->accessor->get(emu, emu_reg_offset(reg)); 3577ec681f3Smrg return val; 3587ec681f3Smrg} 3597ec681f3Smrg 3607ec681f3Smrgvoid 3617ec681f3Smrgemu_set_reg32(struct emu *emu, struct emu_reg *reg, uint32_t val) 3627ec681f3Smrg{ 3637ec681f3Smrg reg->accessor->set(emu, emu_reg_offset(reg), val); 3647ec681f3Smrg} 3657ec681f3Smrg 3667ec681f3Smrgvoid 3677ec681f3Smrgemu_set_reg64(struct emu *emu, struct emu_reg *reg, uint64_t val) 3687ec681f3Smrg{ 3697ec681f3Smrg reg->accessor->set(emu, emu_reg_offset(reg), val); 3707ec681f3Smrg reg->accessor->set(emu, emu_reg_offset(reg) + 1, val >> 32); 3717ec681f3Smrg} 372