freedreno/afuc: Add separate "SQE registers"
It seems like starting with a6xx, the SQE has a special register space for reading/writing the state of the processor itself, mainly used for saving/restoring its state in preemption. Add support for disassembling it, removing one of the unknown flags bits. Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/26691>
This commit is contained in:
parent
7c919f0406
commit
da3cf26564
18 changed files with 420 additions and 163 deletions
|
|
@ -2,7 +2,7 @@
|
|||
; Version: 01000001
|
||||
|
||||
[01000001]
|
||||
[01000078]
|
||||
[0100007e]
|
||||
mov $01, 0x830 ; CP_SQE_INSTR_BASE
|
||||
mov $02, 0x2
|
||||
cwrite $01, [$00 + @REG_READ_ADDR], 0x0
|
||||
|
|
@ -56,27 +56,35 @@ mov $02, 0xff
|
|||
waitin
|
||||
mov $01, $data
|
||||
|
||||
CP_SET_SECURE_MODE:
|
||||
mov $02, $data
|
||||
setsecure $02, #l52
|
||||
l50:
|
||||
jump #l50
|
||||
nop
|
||||
l52:
|
||||
CP_SET_BIN_DATA5:
|
||||
sread $02, [$00 + %SP], 0x0
|
||||
swrite $02, [$00 + %SP], 0x0
|
||||
mov $02, 0x7
|
||||
(rep)swrite $data, [$02 + 0x001], 0x4
|
||||
waitin
|
||||
mov $01, $data
|
||||
|
||||
fxn54:
|
||||
l54:
|
||||
CP_SET_SECURE_MODE:
|
||||
mov $02, $data
|
||||
setsecure $02, #l58
|
||||
l56:
|
||||
jump #l56
|
||||
nop
|
||||
l58:
|
||||
waitin
|
||||
mov $01, $data
|
||||
|
||||
fxn60:
|
||||
l60:
|
||||
cmp $04, $02, $03
|
||||
breq $04, b0, #l61
|
||||
brne $04, b1, #l59
|
||||
breq $04, b2, #l54
|
||||
breq $04, b0, #l67
|
||||
brne $04, b1, #l65
|
||||
breq $04, b2, #l60
|
||||
sub $03, $03, $02
|
||||
l59:
|
||||
jump #l54
|
||||
l65:
|
||||
jump #l60
|
||||
sub $02, $02, $03
|
||||
l61:
|
||||
l67:
|
||||
ret
|
||||
nop
|
||||
|
||||
|
|
@ -85,7 +93,7 @@ cwrite $data, [$00 + @REG_READ_ADDR], 0x0
|
|||
add $02, $regdata, 0x42
|
||||
addhi $03, $00, $regdata
|
||||
sub $02, $02, $regdata
|
||||
call #fxn54
|
||||
call #fxn60
|
||||
subhi $03, $03, $regdata
|
||||
and $02, $02, $regdata
|
||||
or $02, $02, 0x1
|
||||
|
|
@ -110,14 +118,14 @@ mov $03, $data
|
|||
mov $04, $data
|
||||
mov $05, $data
|
||||
mov $06, $data
|
||||
l90:
|
||||
breq $06, 0x0, #l96
|
||||
l96:
|
||||
breq $06, 0x0, #l102
|
||||
cwrite $03, [$00 + @LOAD_STORE_HI], 0x0
|
||||
load $07, [$02 + 0x4], 0x4
|
||||
cwrite $05, [$00 + @LOAD_STORE_HI], 0x0
|
||||
jump #l90
|
||||
jump #l96
|
||||
store $07, [$04 + 0x4], 0x4
|
||||
l96:
|
||||
l102:
|
||||
waitin
|
||||
mov $01, $data
|
||||
|
||||
|
|
@ -134,15 +142,15 @@ mov $01, $data
|
|||
|
||||
IN_PREEMPT:
|
||||
cread $02, [$00 + 0x101], 0x0
|
||||
brne $02, 0x1, #l116
|
||||
brne $02, 0x1, #l122
|
||||
nop
|
||||
preemptleave #l50
|
||||
preemptleave #l56
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
waitin
|
||||
mov $01, $data
|
||||
l116:
|
||||
l122:
|
||||
iret
|
||||
nop
|
||||
|
||||
|
|
@ -196,7 +204,6 @@ CP_REG_WRITE:
|
|||
CP_REG_WR_NO_CTXT:
|
||||
CP_RUN_OPENCL:
|
||||
CP_SCRATCH_TO_REG:
|
||||
CP_SET_BIN_DATA5:
|
||||
CP_SET_BIN_DATA5_OFFSET:
|
||||
CP_SET_CONSTANT:
|
||||
CP_SET_CTXSWITCH_IB:
|
||||
|
|
@ -268,131 +275,131 @@ UNKN96:
|
|||
UNKN97:
|
||||
waitin
|
||||
mov $01, $data
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[0000006b]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[0000003f]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000025]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000022]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[0000002c]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[00000071]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[00000045]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[00000030]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000062]
|
||||
[00000076]
|
||||
[00000055]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[00000076]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[00000025]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[00000022]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000002c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[00000036]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[00000068]
|
||||
[0000007c]
|
||||
[0000005b]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
[0000007c]
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -94,6 +94,15 @@ mov $02, 0xff
|
|||
waitin
|
||||
mov $01, $data
|
||||
|
||||
CP_SET_BIN_DATA5:
|
||||
; test SQE registers
|
||||
sread $02, [$00 + %SP], 0x0
|
||||
swrite $02, [$00 + %SP], 0x0
|
||||
mov $02, 7
|
||||
(rep)swrite $data, [$02 + 1], 0x4
|
||||
waitin
|
||||
mov $01, $data
|
||||
|
||||
CP_SET_SECURE_MODE:
|
||||
; test setsecure
|
||||
mov $02, $data
|
||||
|
|
@ -244,7 +253,6 @@ CP_IM_LOAD_IMMEDIATE:
|
|||
CP_BLIT:
|
||||
CP_SET_CONSTANT:
|
||||
CP_SET_BIN_DATA5_OFFSET:
|
||||
CP_SET_BIN_DATA5:
|
||||
UNKN48:
|
||||
CP_RUN_OPENCL:
|
||||
CP_LOAD_STATE6_GEOM:
|
||||
|
|
|
|||
|
|
@ -276,6 +276,17 @@ but on a6xx::
|
|||
cwrite $0b, [$05 + @IB1_BASE+0x1], 0x0
|
||||
cwrite $04, [$05 + @IB1_DWORDS], 0x0
|
||||
|
||||
.. _afuc-sqe-regs:
|
||||
|
||||
SQE Registers
|
||||
=============
|
||||
|
||||
Starting with a6xx, the state of the SQE processor itself can be accessed
|
||||
through ``sread``/``swrite`` instructions that work identically to
|
||||
``cread``/``cwrite``. For example, this includes the state of the
|
||||
``call``/``ret`` stack. This is mainly used during the preemption routine but
|
||||
it's also used to set the entrypoint for preemption.
|
||||
|
||||
.. _afuc-read:
|
||||
|
||||
Reading Memory and Registers
|
||||
|
|
|
|||
|
|
@ -103,6 +103,13 @@ typedef enum {
|
|||
OPC_STORE,
|
||||
OPC_LOAD,
|
||||
|
||||
/* A6xx added new opcodes that let you read/write the state of the
|
||||
* SQE processor itself, like the call stack. This is mostly used by
|
||||
* preemption but is also used to set the preempt routine entrypoint.
|
||||
*/
|
||||
OPC_SREAD,
|
||||
OPC_SWRITE,
|
||||
|
||||
OPC_BRNEI, /* relative branch (if $src != immed) */
|
||||
OPC_BREQI, /* relative branch (if $src == immed) */
|
||||
OPC_BRNEB, /* relative branch (if bit not set) */
|
||||
|
|
@ -172,6 +179,7 @@ struct afuc_instr {
|
|||
};
|
||||
|
||||
void print_control_reg(uint32_t id);
|
||||
void print_sqe_reg(uint32_t id);
|
||||
void print_pipe_reg(uint32_t id);
|
||||
|
||||
#endif /* _AFUC_H_ */
|
||||
|
|
|
|||
|
|
@ -670,6 +670,25 @@ SOFTWARE.
|
|||
<gen min="6"/>
|
||||
</bitset>
|
||||
|
||||
<bitset name="swrite" extends="#control">
|
||||
<doc>Write to a SQE register.</doc>
|
||||
<gen min="6"/>
|
||||
<display>
|
||||
{REP}swrite {SRC}, [{OFFSET} + {SQEREG}], 0x{FLAGS}
|
||||
</display>
|
||||
|
||||
<field name="SQEREG" low="0" high="11" type="custom"/>
|
||||
<field name="SRC" low="16" high="20" type="#src"/>
|
||||
<pattern pos="15">1</pattern>
|
||||
<pattern low="27" high="31">10101</pattern>
|
||||
|
||||
<encode>
|
||||
<map name="SRC">src->src1</map>
|
||||
<map name="OFFSET">src->src2</map>
|
||||
<map name="SQEREG">src->immed</map>
|
||||
</encode>
|
||||
</bitset>
|
||||
|
||||
<bitset name="load" extends="#control">
|
||||
<gen min="6"/>
|
||||
<doc>
|
||||
|
|
@ -719,6 +738,25 @@ SOFTWARE.
|
|||
<pattern low="27" high="31">10111</pattern>
|
||||
</bitset>
|
||||
|
||||
<bitset name="sread" extends="#control">
|
||||
<doc>Read from a SQE register.</doc>
|
||||
<gen min="6"/>
|
||||
<display>
|
||||
{REP}sread {DST}, [{OFFSET} + {SQEREG}], 0x{FLAGS}
|
||||
</display>
|
||||
|
||||
<field name="SQEREG" low="0" high="11" type="custom"/>
|
||||
<field name="DST" low="16" high="20" type="#dst"/>
|
||||
|
||||
<encode>
|
||||
<map name="OFFSET">src->src1</map>
|
||||
<map name="SQEREG">src->immed</map>
|
||||
</encode>
|
||||
|
||||
<pattern pos="15">1</pattern>
|
||||
<pattern low="27" high="31">10111</pattern>
|
||||
</bitset>
|
||||
|
||||
<bitset name="#branch" extends="#instruction">
|
||||
<field name="OFFSET" low="0" high="15" type="branch"/>
|
||||
<field name="SRC" low="21" high="25" type="#src"/>
|
||||
|
|
|
|||
|
|
@ -210,6 +210,13 @@ parse_control_reg(const char *name)
|
|||
return afuc_control_reg(name + 1);
|
||||
}
|
||||
|
||||
unsigned
|
||||
parse_sqe_reg(const char *name)
|
||||
{
|
||||
/* skip leading "%" */
|
||||
return afuc_sqe_reg(name + 1);
|
||||
}
|
||||
|
||||
static void
|
||||
emit_jumptable(int outfd)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@ parse_bit(const char *str)
|
|||
}
|
||||
|
||||
unsigned parse_control_reg(const char *name);
|
||||
unsigned parse_sqe_reg(const char *name);
|
||||
|
||||
/* string trailing ':' off label: */
|
||||
static inline const char *
|
||||
|
|
|
|||
|
|
@ -88,6 +88,18 @@ print_control_reg(uint32_t id)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
print_sqe_reg(uint32_t id)
|
||||
{
|
||||
char *name = afuc_sqe_reg_name(id);
|
||||
if (name) {
|
||||
printf("@%s", name);
|
||||
free(name);
|
||||
} else {
|
||||
printf("0x%03x", id);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
print_pipe_reg(uint32_t id)
|
||||
{
|
||||
|
|
@ -118,6 +130,14 @@ field_print_cb(struct isa_print_state *state, const char *field_name, uint64_t v
|
|||
} else {
|
||||
isa_print(state, "0x%03x", (unsigned)val);
|
||||
}
|
||||
} else if (!strcmp(field_name, "SQEREG")) {
|
||||
char *name = afuc_sqe_reg_name(val);
|
||||
if (name) {
|
||||
isa_print(state, "%%%s", name);
|
||||
free(name);
|
||||
} else {
|
||||
isa_print(state, "0x%03x", (unsigned)val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -106,6 +106,21 @@ emu_set_control_reg(struct emu *emu, unsigned n, uint32_t val)
|
|||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
emu_get_sqe_reg(struct emu *emu, unsigned n)
|
||||
{
|
||||
assert(n < ARRAY_SIZE(emu->sqe_regs.val));
|
||||
return emu->sqe_regs.val[n];
|
||||
}
|
||||
|
||||
void
|
||||
emu_set_sqe_reg(struct emu *emu, unsigned n, uint32_t val)
|
||||
{
|
||||
assert(n < ARRAY_SIZE(emu->sqe_regs.val));
|
||||
BITSET_SET(emu->sqe_regs.written, n);
|
||||
emu->sqe_regs.val[n] = val;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
emu_get_pipe_reg(struct emu *emu, unsigned n)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -223,6 +223,28 @@ dump_control_register(struct emu *emu, unsigned n)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dump_sqe_register(struct emu *emu, unsigned n)
|
||||
{
|
||||
printf(" SQE: ");
|
||||
print_sqe_reg(n);
|
||||
printf(": ");
|
||||
if (BITSET_TEST(emu->sqe_regs.written, n)) {
|
||||
printdelta("%08x\n", emu->sqe_regs.val[n]);
|
||||
} else {
|
||||
printf("%08x\n", emu->sqe_regs.val[n]);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dump_sqe_registers(struct emu *emu)
|
||||
{
|
||||
for (unsigned i = 0; i < ARRAY_SIZE(emu->sqe_regs.val); i++) {
|
||||
dump_sqe_register(emu, i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
dump_gpumem(struct emu *emu, uintptr_t addr)
|
||||
{
|
||||
|
|
@ -289,6 +311,24 @@ emu_dump_control_prompt(struct emu *emu)
|
|||
dump_control_register(emu, offset);
|
||||
}
|
||||
|
||||
static void
|
||||
emu_write_sqe_prompt(struct emu *emu)
|
||||
{
|
||||
clear_line();
|
||||
printf(" SQE register (name or offset) and value: ");
|
||||
|
||||
const char *name;
|
||||
const char *value;
|
||||
|
||||
if (read_two_values(&name, &value))
|
||||
return;
|
||||
|
||||
unsigned offset = afuc_sqe_reg(name);
|
||||
uint32_t val = strtoul(value, NULL, 0);
|
||||
|
||||
emu_set_sqe_reg(emu, offset, val);
|
||||
}
|
||||
|
||||
static void
|
||||
emu_write_gpu_prompt(struct emu *emu)
|
||||
{
|
||||
|
|
@ -364,7 +404,7 @@ emu_dump_prompt(struct emu *emu)
|
|||
{
|
||||
do {
|
||||
clear_line();
|
||||
printf(" dump: GPR (r)egisters, (c)ontrol register, (g)pu register, (m)emory: ");
|
||||
printf(" dump: GPR (r)egisters, (c)ontrol register, (s)qe registers, (g)pu register, (m)emory: ");
|
||||
|
||||
int c = readchar();
|
||||
printf("%c\n", c);
|
||||
|
|
@ -375,6 +415,10 @@ emu_dump_prompt(struct emu *emu)
|
|||
*/
|
||||
dump_gpr_registers(emu);
|
||||
break;
|
||||
} else if (c == 's') {
|
||||
/* Similarly, just dump all the SQE registers */
|
||||
dump_sqe_registers(emu);
|
||||
break;
|
||||
} else if (c == 'c') {
|
||||
emu_dump_control_prompt(emu);
|
||||
break;
|
||||
|
|
@ -396,7 +440,7 @@ emu_write_prompt(struct emu *emu)
|
|||
{
|
||||
do {
|
||||
clear_line();
|
||||
printf(" write: GPR (r)egister, (c)ontrol register, (g)pu register, (m)emory: ");
|
||||
printf(" write: GPR (r)egister, (c)ontrol register, (s)sqe register, (g)pu register, (m)emory: ");
|
||||
|
||||
int c = readchar();
|
||||
printf("%c\n", c);
|
||||
|
|
@ -404,6 +448,9 @@ emu_write_prompt(struct emu *emu)
|
|||
if (c == 'r') {
|
||||
emu_write_gpr_prompt(emu);
|
||||
break;
|
||||
} else if (c == 's') {
|
||||
emu_write_sqe_prompt(emu);
|
||||
break;
|
||||
} else if (c == 'c') {
|
||||
emu_write_control_prompt(emu);
|
||||
break;
|
||||
|
|
@ -512,6 +559,7 @@ void
|
|||
emu_clear_state_change(struct emu *emu)
|
||||
{
|
||||
memset(emu->control_regs.written, 0, sizeof(emu->control_regs.written));
|
||||
memset(emu->sqe_regs.written, 0, sizeof(emu->sqe_regs.written));
|
||||
memset(emu->pipe_regs.written, 0, sizeof(emu->pipe_regs.written));
|
||||
memset(emu->gpu_regs.written, 0, sizeof(emu->gpu_regs.written));
|
||||
memset(emu->gpr_regs.written, 0, sizeof(emu->gpr_regs.written));
|
||||
|
|
@ -543,6 +591,10 @@ emu_dump_state_change(struct emu *emu)
|
|||
dump_control_register(emu, i);
|
||||
}
|
||||
|
||||
BITSET_FOREACH_SET (i, emu->sqe_regs.written, EMU_NUM_SQE_REGS) {
|
||||
dump_sqe_register(emu, i);
|
||||
}
|
||||
|
||||
if (emu->gpumem_written != ~0) {
|
||||
dump_gpumem(emu, emu->gpumem_written);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -235,6 +235,32 @@ emu_instr(struct emu *emu, struct afuc_instr *instr)
|
|||
emu_get_control_reg(emu, src1 + instr->immed));
|
||||
break;
|
||||
}
|
||||
case OPC_SWRITE: {
|
||||
uint32_t src1 = emu_get_gpr_reg(emu, instr->src1);
|
||||
uint32_t src2 = emu_get_gpr_reg(emu, instr->src2);
|
||||
|
||||
if (instr->bit == 0x4) {
|
||||
emu_set_gpr_reg(emu, instr->src2, src2 + instr->immed);
|
||||
} else if (instr->bit && !emu->quiet) {
|
||||
printf("unhandled flags: %x\n", instr->bit);
|
||||
}
|
||||
|
||||
emu_set_sqe_reg(emu, src2 + instr->immed, src1);
|
||||
break;
|
||||
}
|
||||
case OPC_SREAD: {
|
||||
uint32_t src1 = emu_get_gpr_reg(emu, instr->src1);
|
||||
|
||||
if (instr->bit == 0x4) {
|
||||
emu_set_gpr_reg(emu, instr->src1, src1 + instr->immed);
|
||||
} else if (instr->bit && !emu->quiet) {
|
||||
printf("unhandled flags: %x\n", instr->bit);
|
||||
}
|
||||
|
||||
emu_set_gpr_reg(emu, instr->dst,
|
||||
emu_get_sqe_reg(emu, src1 + instr->immed));
|
||||
break;
|
||||
}
|
||||
case OPC_LOAD: {
|
||||
uintptr_t addr = load_store_addr(emu, instr->src1) +
|
||||
instr->immed;
|
||||
|
|
|
|||
|
|
@ -48,6 +48,13 @@ struct emu_control_regs {
|
|||
uint32_t val[EMU_NUM_CONTROL_REGS];
|
||||
};
|
||||
|
||||
#define EMU_NUM_SQE_REGS 0x10
|
||||
|
||||
struct emu_sqe_regs {
|
||||
BITSET_DECLARE(written, EMU_NUM_SQE_REGS);
|
||||
uint32_t val[EMU_NUM_SQE_REGS];
|
||||
};
|
||||
|
||||
#define EMU_NUM_GPU_REGS 0x10000
|
||||
|
||||
struct emu_gpu_regs {
|
||||
|
|
@ -166,6 +173,7 @@ struct emu {
|
|||
unsigned gpu_id;
|
||||
|
||||
struct emu_control_regs control_regs;
|
||||
struct emu_sqe_regs sqe_regs;
|
||||
struct emu_pipe_regs pipe_regs;
|
||||
struct emu_gpu_regs gpu_regs;
|
||||
struct emu_gpr_regs gpr_regs;
|
||||
|
|
@ -185,7 +193,9 @@ struct emu {
|
|||
/* (r)un mode, don't stop for input until next waitin: */
|
||||
bool run_mode;
|
||||
|
||||
/* carry-bits for add/sub for addhi/subhi */
|
||||
/* carry-bits for add/sub for addhi/subhi
|
||||
* TODO: this is probably in a SQE register somewhere
|
||||
*/
|
||||
uint32_t carry;
|
||||
|
||||
/* call-stack of saved PCs.. I expect this to be a fixed size, but not
|
||||
|
|
@ -252,6 +262,9 @@ void emu_set_gpu_reg(struct emu *emu, unsigned n, uint32_t val);
|
|||
uint32_t emu_get_control_reg(struct emu *emu, unsigned n);
|
||||
void emu_set_control_reg(struct emu *emu, unsigned n, uint32_t val);
|
||||
|
||||
uint32_t emu_get_sqe_reg(struct emu *emu, unsigned n);
|
||||
void emu_set_sqe_reg(struct emu *emu, unsigned n, uint32_t val);
|
||||
|
||||
/* Register helpers for fixed fxn emulation, to avoid lots of boilerplate
|
||||
* for accessing other pipe/control registers.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ extern YYSTYPE yylval;
|
|||
"$"[a-zA-Z][a-zA-Z0-9]* yylval.num = parse_reg(yytext); return T_REGISTER;
|
||||
"b"[0-9][0-9]* yylval.num = parse_bit(yytext); return T_BIT;
|
||||
"@"[a-zA-Z_][a-zA-Z0-9_]* yylval.num = parse_control_reg(yytext); return T_CONTROL_REG;
|
||||
"%"[a-zA-Z_][a-zA-Z0-9_]* yylval.num = parse_sqe_reg(yytext); return T_SQE_REG;
|
||||
"#"[a-zA-Z_][a-zA-Z0-9_]* yylval.str = strdup(yytext+1); return T_LABEL_REF; /* label reference */
|
||||
[a-zA-Z_][a-zA-Z0-9_]*":" yylval.str = parse_label_decl(yytext); return T_LABEL_DECL; /* label declaration */
|
||||
"["[0-9a-fA-F][0-9a-fA-F]*"]" yylval.num = parse_literal(yytext); return T_LITERAL;
|
||||
|
|
@ -78,6 +79,8 @@ extern YYSTYPE yylval;
|
|||
"mov" return TOKEN(T_OP_MOV);
|
||||
"cwrite" return TOKEN(T_OP_CWRITE);
|
||||
"cread" return TOKEN(T_OP_CREAD);
|
||||
"swrite" return TOKEN(T_OP_SWRITE);
|
||||
"sread" return TOKEN(T_OP_SREAD);
|
||||
"store" return TOKEN(T_OP_STORE);
|
||||
"load" return TOKEN(T_OP_LOAD);
|
||||
"brne" return TOKEN(T_OP_BRNE);
|
||||
|
|
|
|||
|
|
@ -121,6 +121,7 @@ label(const char *str)
|
|||
%token <num> T_INT
|
||||
%token <num> T_HEX
|
||||
%token <num> T_CONTROL_REG
|
||||
%token <num> T_SQE_REG
|
||||
%token <str> T_LABEL_DECL
|
||||
%token <str> T_LABEL_REF
|
||||
%token <num> T_LITERAL
|
||||
|
|
@ -153,6 +154,8 @@ label(const char *str)
|
|||
%token <tok> T_OP_MOV
|
||||
%token <tok> T_OP_CWRITE
|
||||
%token <tok> T_OP_CREAD
|
||||
%token <tok> T_OP_SWRITE
|
||||
%token <tok> T_OP_SREAD
|
||||
%token <tok> T_OP_STORE
|
||||
%token <tok> T_OP_LOAD
|
||||
%token <tok> T_OP_BRNE
|
||||
|
|
@ -254,8 +257,10 @@ alu_instr: alu_2src_instr
|
|||
|
||||
load_op: T_OP_LOAD { new_instr(OPC_LOAD); }
|
||||
| T_OP_CREAD { new_instr(OPC_CREAD); }
|
||||
| T_OP_SREAD { new_instr(OPC_SREAD); }
|
||||
store_op: T_OP_STORE { new_instr(OPC_STORE); }
|
||||
| T_OP_CWRITE { new_instr(OPC_CWRITE); }
|
||||
| T_OP_SWRITE { new_instr(OPC_SWRITE); }
|
||||
|
||||
load_instr: load_op reg ',' '[' reg '+' immediate ']' ',' immediate {
|
||||
dst($2); src1($5); immed($7); bit($10);
|
||||
|
|
@ -286,4 +291,6 @@ immediate: T_HEX
|
|||
| T_INT
|
||||
| T_CONTROL_REG
|
||||
| T_CONTROL_REG '+' immediate { $$ = $1 + $3; }
|
||||
| T_SQE_REG
|
||||
| T_SQE_REG '+' immediate { $$ = $1 + $3; }
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
static struct rnndeccontext *ctx;
|
||||
static struct rnndb *db;
|
||||
static struct rnndomain *control_regs;
|
||||
static struct rnndomain *sqe_regs;
|
||||
static struct rnndomain *pipe_regs;
|
||||
struct rnndomain *dom[2];
|
||||
static struct rnnenum *pm4_packets;
|
||||
|
|
@ -86,6 +87,24 @@ afuc_control_reg(const char *name)
|
|||
return reg(control_regs, "control", name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Map offset to SQE reg name (or NULL), caller frees
|
||||
*/
|
||||
char *
|
||||
afuc_sqe_reg_name(unsigned id)
|
||||
{
|
||||
return reg_name(sqe_regs, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Map SQE reg name to offset.
|
||||
*/
|
||||
unsigned
|
||||
afuc_sqe_reg(const char *name)
|
||||
{
|
||||
return reg(sqe_regs, "SQE", name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Map offset to control reg name (or NULL), caller frees
|
||||
*/
|
||||
|
|
@ -292,6 +311,7 @@ int afuc_util_init(int gpuver, bool colors)
|
|||
dom[0] = rnn_finddomain(db, name);
|
||||
dom[1] = rnn_finddomain(db, "AXXX");
|
||||
control_regs = rnn_finddomain(db, control_reg_name);
|
||||
sqe_regs = rnn_finddomain(db, "A6XX_SQE_REG");
|
||||
pipe_regs = rnn_finddomain(db, pipe_reg_name);
|
||||
|
||||
rnndec_varadd(ctx, "chip", variant);
|
||||
|
|
|
|||
|
|
@ -33,6 +33,9 @@
|
|||
unsigned afuc_control_reg(const char *name);
|
||||
char * afuc_control_reg_name(unsigned id);
|
||||
|
||||
unsigned afuc_sqe_reg(const char *name);
|
||||
char * afuc_sqe_reg_name(unsigned id);
|
||||
|
||||
unsigned afuc_pipe_reg(const char *name);
|
||||
char * afuc_pipe_reg_name(unsigned id);
|
||||
bool afuc_pipe_reg_is_void(unsigned id);
|
||||
|
|
|
|||
|
|
@ -4,10 +4,34 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|||
xsi:schemaLocation="http://nouveau.freedesktop.org/ rules-ng.xsd">
|
||||
|
||||
<!--
|
||||
This documents the internal register space used by the CP firmware since
|
||||
This documents the internal register spaces used by the CP firmware since
|
||||
the afuc instruction set was introduced.
|
||||
-->
|
||||
|
||||
<domain name="A6XX_SQE_REG" width="32">
|
||||
<!-- TODO: the carry flag is probably here somewhere -->
|
||||
|
||||
<doc>
|
||||
Instruction to jump to when the CP is preempted to perform a
|
||||
context switch, initialized to entry 15 of the jump table at
|
||||
bootup.
|
||||
</doc>
|
||||
<reg32 name="PREEMPT_INSTR" offset="0x04"/>
|
||||
|
||||
<doc> Stack Pointer for call/ret return address stack </doc>
|
||||
<reg32 name="SP" offset="0x05"/>
|
||||
|
||||
<!-- TODO: make asm can handle arrays so we can use an array here -->
|
||||
<reg32 name="STACK0" offset="0x08" type="hex"/>
|
||||
<reg32 name="STACK1" offset="0x09" type="hex"/>
|
||||
<reg32 name="STACK2" offset="0x0a" type="hex"/>
|
||||
<reg32 name="STACK3" offset="0x0b" type="hex"/>
|
||||
<reg32 name="STACK4" offset="0x0c" type="hex"/>
|
||||
<reg32 name="STACK5" offset="0x0d" type="hex"/>
|
||||
<reg32 name="STACK6" offset="0x0e" type="hex"/>
|
||||
<reg32 name="STACK7" offset="0x0f" type="hex"/>
|
||||
</domain>
|
||||
|
||||
<domain name="A5XX_CONTROL_REG" width="32">
|
||||
<reg32 name="REG_WRITE_ADDR" offset="0x010"/>
|
||||
<reg32 name="REG_WRITE" offset="0x011"/>
|
||||
|
|
@ -30,12 +54,6 @@ xsi:schemaLocation="http://nouveau.freedesktop.org/ rules-ng.xsd">
|
|||
|
||||
<domain name="A6XX_CONTROL_REG" width="32">
|
||||
<reg32 name="RB_RPTR" offset="0x001"/>
|
||||
<doc>
|
||||
Instruction to jump to when the CP is preempted to perform a
|
||||
context switch, initialized to entry 15 of the jump table at
|
||||
bootup.
|
||||
</doc>
|
||||
<reg32 name="PREEMPT_INSTR" offset="0x004"/>
|
||||
|
||||
<reg64 name="IB1_BASE" offset="0x010"/>
|
||||
<reg32 name="IB1_DWORDS" offset="0x012"/>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue