diff --git a/src/freedreno/.gitlab-ci/reference/afuc_test.asm b/src/freedreno/.gitlab-ci/reference/afuc_test.asm
index bd3ac583838..93c70878dc9 100644
--- a/src/freedreno/.gitlab-ci/reference/afuc_test.asm
+++ b/src/freedreno/.gitlab-ci/reference/afuc_test.asm
@@ -52,7 +52,7 @@ mov $01, $data
CP_SCRATCH_WRITE:
mov $02, 0xff
-(rep)cwrite $data, [$02 + @RB_RPTR], 0x4
+(rep)cwrite $data, [$02 + 0x1]!, 0x0
waitin
mov $01, $data
@@ -60,7 +60,7 @@ CP_SET_BIN_DATA5:
sread $02, [$00 + %SP], 0x0
swrite $02, [$00 + %SP], 0x0
mov $02, 0x7
-(rep)swrite $data, [$02 + 0x001], 0x4
+(rep)swrite $data, [$02 + 0x1]!, 0x0
waitin
mov $01, $data
@@ -121,10 +121,10 @@ mov $06, $data
l96:
breq $06, 0x0, #l102
cwrite $03, [$00 + @LOAD_STORE_HI], 0x0
-load $07, [$02 + 0x4], 0x4
+load $07, [$02 + 0x4]!, 0x0
cwrite $05, [$00 + @LOAD_STORE_HI], 0x0
jump #l96
-store $07, [$04 + 0x4], 0x4
+store $07, [$04 + 0x4]!, 0x0
l102:
waitin
mov $01, $data
@@ -136,7 +136,7 @@ mov $02, $data
cwrite $data, [$00 + @LOAD_STORE_HI], 0x0
mov $rem, $data
cwrite $rem, [$00 + @MEM_READ_DWORDS], 0x0
-(rep)store $memdata, [$02 + 0x4], 0x4
+(rep)store $memdata, [$02 + 0x4]!, 0x0
waitin
mov $01, $data
diff --git a/src/freedreno/.gitlab-ci/traces/afuc_test.asm b/src/freedreno/.gitlab-ci/traces/afuc_test.asm
index 3d1997d54e1..c5bb18072bd 100644
--- a/src/freedreno/.gitlab-ci/traces/afuc_test.asm
+++ b/src/freedreno/.gitlab-ci/traces/afuc_test.asm
@@ -90,7 +90,7 @@ CP_SCRATCH_WRITE:
; test (rep) + flags + non-zero offset with cwrite
; TODO: 0x4 flag is actually pre-increment addressing, handle it as such
mov $02, 0xff
-(rep)cwrite $data, [$02 + 0x001], 0x4
+(rep)cwrite $data, [$02 + 0x001]!, 0x0
waitin
mov $01, $data
@@ -99,7 +99,7 @@ CP_SET_BIN_DATA5:
sread $02, [$00 + %SP], 0x0
swrite $02, [$00 + %SP], 0x0
mov $02, 7
-(rep)swrite $data, [$02 + 1], 0x4
+(rep)swrite $data, [$02 + 1]!, 0x0
waitin
mov $01, $data
@@ -172,10 +172,10 @@ mov $06, $data
cpy_header:
breq $06, 0, #cpy_exit
cwrite $03, [$00 + @LOAD_STORE_HI], 0x0
-load $07, [$02 + 0x004], 0x4
+load $07, [$02 + 0x004]!, 0x0
cwrite $05, [$00 + @LOAD_STORE_HI], 0x0
jump #cpy_header
-store $07, [$04 + 0x004], 0x4
+store $07, [$04 + 0x004]!, 0x0
cpy_exit:
waitin
mov $01, $data
@@ -189,7 +189,7 @@ mov $02, $data
cwrite $data, [$00 + @LOAD_STORE_HI], 0x0
mov $rem, $data
cwrite $rem, [$00 + @MEM_READ_DWORDS], 0x0
-(rep)store $memdata, [$02 + 0x004], 0x4
+(rep)store $memdata, [$02 + 0x004]!, 0x0
waitin
mov $01, $data
diff --git a/src/freedreno/afuc/README.rst b/src/freedreno/afuc/README.rst
index e8f5fd35a30..00f99a328c2 100644
--- a/src/freedreno/afuc/README.rst
+++ b/src/freedreno/afuc/README.rst
@@ -224,7 +224,9 @@ Control registers are a special register space that can only be read/written
directly by CP through ``cread``/``cwrite`` instructions::
- ``cread $dst, [$off + addr], flags``
+- ``cread $dst, [$off + addr]!, flags``
- ``cwrite $src, [$off + addr], flags``
+- ``cwrite $src, [$off + addr]!, flags``
Control registers ``0x000`` to ``0x0ff`` are private registers used to control
the CP, for example to indicate where to read from memory or (normal)
@@ -235,8 +237,8 @@ packets.
In cases where no offset is needed, ``$00`` is frequently used as the offset.
-A value of 4 for ``flags`` is known to be a pre-increment mode that writes the
-final address ``$off + addr`` to ``$off``, it's not known what other values do.
+The addressing mode with ``!`` is a pre-increment mode that writes the final
+address ``$off + addr`` to ``$off``.
For example, the following sequences sets::
diff --git a/src/freedreno/afuc/afuc.h b/src/freedreno/afuc/afuc.h
index 2a2f4157bf6..dc082c9181a 100644
--- a/src/freedreno/afuc/afuc.h
+++ b/src/freedreno/afuc/afuc.h
@@ -176,6 +176,7 @@ struct afuc_instr {
bool has_bit : 1;
bool is_literal : 1;
bool rep : 1;
+ bool preincrement : 1;
};
void print_control_reg(uint32_t id);
diff --git a/src/freedreno/afuc/afuc.xml b/src/freedreno/afuc/afuc.xml
index e07ae81bc08..303c472aefd 100644
--- a/src/freedreno/afuc/afuc.xml
+++ b/src/freedreno/afuc/afuc.xml
@@ -603,17 +603,19 @@ SOFTWARE.
-
+
+
+
- {REP}store {SRC}, [{OFFSET} + 0x{IMMED}], 0x{FLAGS}
+ {REP}store {SRC}, [{OFFSET} + 0x{IMMED}]{PREINCREMENT}, 0x{FLAGS}
@@ -643,20 +645,48 @@ SOFTWARE.
10100
+
+ {PREINCREMENT}
+
+
+
+
+
+
+ 0x{IMMED}
+
+
+
+
+ {CONTROLREG}
+
+
+
+
+
+
+
+
+
Write to a control register.
- {REP}cwrite {SRC}, [{OFFSET} + {CONTROLREG}], 0x{FLAGS}
+ {REP}cwrite {SRC}, [{OFFSET} + {BASE}]{PREINCREMENT}, 0x{FLAGS}
-
+
+
+
10101
-
+
@@ -670,14 +700,33 @@ SOFTWARE.
+
+
+
+ 0x{IMMED}
+
+
+
+
+ {SQEREG}
+
+
+
+
+
+
+
+
Write to a SQE register.
- {REP}swrite {SRC}, [{OFFSET} + {SQEREG}], 0x{FLAGS}
+ {REP}swrite {SRC}, [{OFFSET} + {BASE}]{PREINCREMENT}, 0x{FLAGS}
-
+
+
+
1
10101
@@ -685,7 +734,7 @@ SOFTWARE.
-
+
@@ -697,7 +746,7 @@ SOFTWARE.
restored.
- {REP}load {DST}, [{OFFSET} + 0x{IMMED}], 0x{FLAGS}
+ {REP}load {DST}, [{OFFSET} + 0x{IMMED}]{PREINCREMENT}, 0x{FLAGS}
@@ -713,15 +762,17 @@ SOFTWARE.
Read from a control register.
- {REP}cread {DST}, [{OFFSET} + {CONTROLREG}], 0x{FLAGS}
+ {REP}cread {DST}, [{OFFSET} + {BASE}]{PREINCREMENT}, 0x{FLAGS}
-
+
+
+
-
+
@@ -742,15 +793,17 @@ SOFTWARE.
Read from a SQE register.
- {REP}sread {DST}, [{OFFSET} + {SQEREG}], 0x{FLAGS}
+ {REP}sread {DST}, [{OFFSET} + {BASE}]{PREINCREMENT}, 0x{FLAGS}
-
+
+
+
-
+
1
diff --git a/src/freedreno/afuc/emu.c b/src/freedreno/afuc/emu.c
index 796b879c4a8..633ba6b76a0 100644
--- a/src/freedreno/afuc/emu.c
+++ b/src/freedreno/afuc/emu.c
@@ -216,7 +216,7 @@ emu_instr(struct emu *emu, struct afuc_instr *instr)
uint32_t src1 = emu_get_gpr_reg(emu, instr->src1);
uint32_t src2 = emu_get_gpr_reg(emu, instr->src2);
- if (instr->bit == 0x4) {
+ if (instr->preincrement) {
emu_set_gpr_reg(emu, instr->src2, src2 + instr->immed);
} else if (instr->bit && !emu->quiet) {
printf("unhandled flags: %x\n", instr->bit);
@@ -228,7 +228,7 @@ emu_instr(struct emu *emu, struct afuc_instr *instr)
case OPC_CREAD: {
uint32_t src1 = emu_get_gpr_reg(emu, instr->src1);
- if (instr->bit == 0x4) {
+ if (instr->preincrement) {
emu_set_gpr_reg(emu, instr->src1, src1 + instr->immed);
} else if (instr->bit && !emu->quiet) {
printf("unhandled flags: %x\n", instr->bit);
@@ -242,7 +242,7 @@ emu_instr(struct emu *emu, struct afuc_instr *instr)
uint32_t src1 = emu_get_gpr_reg(emu, instr->src1);
uint32_t src2 = emu_get_gpr_reg(emu, instr->src2);
- if (instr->bit == 0x4) {
+ if (instr->preincrement) {
emu_set_gpr_reg(emu, instr->src2, src2 + instr->immed);
} else if (instr->bit && !emu->quiet) {
printf("unhandled flags: %x\n", instr->bit);
@@ -254,7 +254,7 @@ emu_instr(struct emu *emu, struct afuc_instr *instr)
case OPC_SREAD: {
uint32_t src1 = emu_get_gpr_reg(emu, instr->src1);
- if (instr->bit == 0x4) {
+ if (instr->preincrement) {
emu_set_gpr_reg(emu, instr->src1, src1 + instr->immed);
} else if (instr->bit && !emu->quiet) {
printf("unhandled flags: %x\n", instr->bit);
@@ -268,7 +268,7 @@ emu_instr(struct emu *emu, struct afuc_instr *instr)
uintptr_t addr = load_store_addr(emu, instr->src1) +
instr->immed;
- if (instr->bit == 0x4) {
+ if (instr->preincrement) {
uint32_t src1 = emu_get_gpr_reg(emu, instr->src1);
emu_set_gpr_reg(emu, instr->src1, src1 + instr->immed);
} else if (instr->bit && !emu->quiet) {
@@ -285,7 +285,7 @@ emu_instr(struct emu *emu, struct afuc_instr *instr)
uintptr_t addr = load_store_addr(emu, instr->src2) +
instr->immed;
- if (instr->bit == 0x4) {
+ if (instr->preincrement) {
uint32_t src2 = emu_get_gpr_reg(emu, instr->src2);
emu_set_gpr_reg(emu, instr->src2, src2 + instr->immed);
} else if (instr->bit && !emu->quiet) {
diff --git a/src/freedreno/afuc/lexer.l b/src/freedreno/afuc/lexer.l
index 5ee639a2972..179b5484b67 100644
--- a/src/freedreno/afuc/lexer.l
+++ b/src/freedreno/afuc/lexer.l
@@ -100,6 +100,7 @@ extern YYSTYPE yylval;
"[" return '[';
"]" return ']';
"+" return '+';
+"!" return '!';
. fprintf(stderr, "error at line %d: Unknown token: %s\n", yyget_lineno(), yytext); yyterminate();
diff --git a/src/freedreno/afuc/parser.y b/src/freedreno/afuc/parser.y
index 5fbfaf2d209..202f45c6ddd 100644
--- a/src/freedreno/afuc/parser.y
+++ b/src/freedreno/afuc/parser.y
@@ -262,11 +262,14 @@ 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);
+preincrement:
+| '!' { instr->preincrement = true; }
+
+load_instr: load_op reg ',' '[' reg '+' immediate ']' preincrement ',' immediate {
+ dst($2); src1($5); immed($7); bit($11);
}
-store_instr: store_op reg ',' '[' reg '+' immediate ']' ',' immediate {
- src1($2); src2($5); immed($7); bit($10);
+store_instr: store_op reg ',' '[' reg '+' immediate ']' preincrement ',' immediate {
+ src1($2); src2($5); immed($7); bit($11);
}
branch_op: T_OP_BRNE { new_instr(OPC_BRNE); }