freedreno/afuc: Decode (peek) modifier

This is an educated guess based on the location it is used in
(CP_INDIRECT_BUFFER).

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/26771>
This commit is contained in:
Connor Abbott 2023-12-18 17:21:43 -05:00 committed by Marge Bot
parent f88c269148
commit 443e8b89ca
8 changed files with 65 additions and 14 deletions

View file

@ -585,6 +585,19 @@ In testing with other control registers, ``(sdsN)`` causes the source to be
read ``N`` extra times and then thrown away. Only when used in combination with
``@DRAW_STATE_SET_HDR`` do the extra source reads have an effect.
.. _afuc-peek:
Peek
----
``(peek)`` is valid on ALU instructions without an immediate. It modifies what
``$data`` (and possibly ``$memdata`` and ``$regdata``) do by making them avoid
consuming the word. The next read to ``$data`` will return the same thing. This
is used solely by ``CP_INDIRECT_BUFFER`` to test if there is a subsequent IB
that can be prefetched while the first IB is executed without actually
consuming the header for the next packet. It is introduced on a7xx, and
replaces the use of a special control register.
Packet Table
============

View file

@ -178,6 +178,7 @@ struct afuc_instr {
bool is_literal : 1;
bool rep : 1;
bool preincrement : 1;
bool peek : 1;
};
void print_control_reg(uint32_t id);

View file

@ -150,15 +150,20 @@ SOFTWARE.
<bitset name="#alu-2src" extends="#instruction-rep">
<display>
{REP}{XMOV}{NAME} {DST}, {SRC1}, {SRC2}
{REP}{XMOV}{PEEK}{NAME} {DST}, {SRC1}, {SRC2}
</display>
<pattern low="5" high="8">xxxx</pattern>
<pattern low="5" high="7">xxx</pattern>
<field name="PEEK" pos="8" type="bool" display="(peek)"/>
<field name="XMOV" low="9" high="10" type="#xmov"/>
<field name="DST" low="11" high="15" type="#dst"/>
<field name="SRC2" low="16" high="20" type="#src"/>
<field name="SRC1" low="21" high="25" type="#src"/>
<pattern low="27" high="31">10011</pattern>
<encode>
<map name="PEEK">src->peek</map>
</encode>
</bitset>
<bitset name="#alu-1src" extends="#instruction-rep">
@ -254,7 +259,7 @@ SOFTWARE.
<override>
<expr>{SRC1} == 0</expr>
<display>
{REP}{XMOV}mov {DST}, {SRC2}
{REP}{XMOV}{PEEK}mov {DST}, {SRC2}
</display>
</override>
<pattern low="0" high="4">00110</pattern>

View file

@ -188,7 +188,7 @@ get_reg_addr(struct emu *emu)
/* Handle reads for special streaming regs: */
static uint32_t
emu_get_fifo_reg(struct emu *emu, unsigned n)
emu_get_fifo_reg(struct emu *emu, unsigned n, bool peek)
{
/* TODO the fifo regs are slurping out of a FIFO that the hw is filling
* in parallel.. we can use `struct emu_queue` to emulate what is actually
@ -203,7 +203,7 @@ emu_get_fifo_reg(struct emu *emu, unsigned n)
unsigned read_dwords = emu_get_reg32(emu, &MEM_READ_DWORDS);
uintptr_t read_addr = emu_get_reg64(emu, &MEM_READ_ADDR);
if (read_dwords > 0) {
if (read_dwords > 0 && !peek) {
emu_set_reg32(emu, &MEM_READ_DWORDS, read_dwords - 1);
emu_set_reg64(emu, &MEM_READ_ADDR, read_addr + 4);
}
@ -221,7 +221,7 @@ emu_get_fifo_reg(struct emu *emu, unsigned n)
* REG_READ_ADDR, it just ends up with a single value written
* into the FIFO that $regdata is consuming from:
*/
if (read_dwords > 0) {
if (read_dwords > 0 && !peek) {
emu_set_reg32(emu, &REG_READ_DWORDS, read_dwords - 1);
emu_set_reg32(emu, &REG_READ_ADDR, read_addr + 1);
}
@ -234,9 +234,14 @@ emu_get_fifo_reg(struct emu *emu, unsigned n)
assert(rem >= 0);
uint32_t val;
if (emu_queue_pop(&emu->roq, &val)) {
emu_set_gpr_reg(emu, REG_REM, --rem);
return val;
if (peek) {
if (emu_queue_peek(&emu->roq, &val))
return val;
} else {
if (emu_queue_pop(&emu->roq, &val)) {
emu_set_gpr_reg(emu, REG_REM, --rem);
return val;
}
}
/* If FIFO is empty, prompt for more input: */
@ -301,7 +306,7 @@ emu_set_fifo_reg(struct emu *emu, unsigned n, uint32_t val)
}
uint32_t
emu_get_gpr_reg(struct emu *emu, unsigned n)
emu_get_gpr_reg_alu(struct emu *emu, unsigned n, bool peek)
{
assert(n < ARRAY_SIZE(emu->gpr_regs.val));
@ -312,12 +317,18 @@ emu_get_gpr_reg(struct emu *emu, unsigned n)
case REG_MEMDATA:
case REG_REGDATA:
case REG_DATA:
return emu_get_fifo_reg(emu, n);
return emu_get_fifo_reg(emu, n, peek);
default:
return emu->gpr_regs.val[n];
}
}
uint32_t
emu_get_gpr_reg(struct emu *emu, unsigned n)
{
return emu_get_gpr_reg_alu(emu, n, false);
}
void
emu_set_gpr_reg(struct emu *emu, unsigned n, uint32_t val)
{

View file

@ -145,7 +145,7 @@ emu_instr(struct emu *emu, struct afuc_instr *instr)
uint32_t val = emu_alu(emu, instr->opc,
emu_get_gpr_reg(emu, instr->src1),
instr->has_immed ? instr->immed :
emu_get_gpr_reg(emu, instr->src2));
emu_get_gpr_reg_alu(emu, instr->src2, instr->peek));
emu_set_gpr_reg(emu, instr->dst, val);
if (instr->xmov) {

View file

@ -108,6 +108,17 @@ emu_queue_pop(struct emu_queue *q, uint32_t *val)
return true;
}
static inline bool
emu_queue_peek(struct emu_queue *q, uint32_t *val)
{
if (!q->count)
return false;
*val = q->fifo[q->tail];
return true;
}
/**
* Draw-state (ie. CP_SET_DRAW_STATE) related emulation
*/
@ -249,6 +260,7 @@ void emu_dump_state_change(struct emu *emu);
/* Registers: */
uint32_t emu_get_gpr_reg(struct emu *emu, unsigned n);
void emu_set_gpr_reg(struct emu *emu, unsigned n, uint32_t val);
uint32_t emu_get_gpr_reg_alu(struct emu *emu, unsigned n, bool peek);
void emu_set_gpu_reg(struct emu *emu, unsigned n, uint32_t val);

View file

@ -96,6 +96,7 @@ extern YYSTYPE yylval;
"(rep)" return TOKEN(T_REP);
"(xmov"[1-3]")" yylval.num = yytext[5] - '0'; return T_XMOV;
"(sds"[1-3]")" yylval.num = yytext[4] - '0'; return T_SDS;
"(peek)" return TOKEN(T_PEEK);
"," return ',';
"[" return '[';

View file

@ -169,11 +169,14 @@ label(const char *str)
%token <tok> T_OP_SETSECURE
%token <tok> T_LSHIFT
%token <tok> T_REP
%token <tok> T_PEEK
%token <num> T_XMOV
%token <num> T_SDS
%type <num> reg
%type <num> immediate
%type <num> xmov
%type <num> peek
%error-verbose
@ -190,9 +193,14 @@ instr_or_label: instr_r
| other_instr
| T_LABEL_DECL { decl_label($1); }
xmov: T_XMOV { $$ = $1; }
| { $$ = 0; }
peek: T_PEEK { $$ = 1; }
| { $$ = 0; }
/* instructions that can optionally have (rep) flag: */
instr_r: alu_instr { instr->xmov = 0; }
| T_XMOV alu_instr { instr->xmov = $1; }
instr_r: xmov peek alu_instr { instr->xmov = $1; instr->peek = $2; }
| load_instr
| store_instr