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:
Connor Abbott 2023-12-12 02:19:20 +01:00 committed by Marge Bot
parent 7c919f0406
commit da3cf26564
18 changed files with 420 additions and 163 deletions

View file

@ -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]

View file

@ -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:

View file

@ -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

View file

@ -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_ */

View file

@ -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"/>

View file

@ -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)
{

View file

@ -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 *

View file

@ -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);
}
}
}

View file

@ -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)
{

View file

@ -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);
}

View file

@ -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;

View file

@ -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.
*

View file

@ -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);

View file

@ -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; }

View file

@ -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);

View file

@ -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);

View file

@ -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"/>