mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-05 00:58:05 +02:00
freedreno/afuc: Handle xmov modifiers
Although it's kind-of similar to "(rptN)" in the shader ISA, I called it "xmov" to make it clear that it's completely orthogonal to "(rep)", although you certainly can use both modifiers on the same instruction. Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6368>
This commit is contained in:
parent
b2b19234d8
commit
66dd248593
6 changed files with 67 additions and 2 deletions
|
|
@ -129,7 +129,8 @@ typedef union PACKED {
|
|||
} movi;
|
||||
struct PACKED {
|
||||
uint32_t alu : 5;
|
||||
uint32_t pad : 6;
|
||||
uint32_t pad : 4;
|
||||
uint32_t xmov : 2; /* execute eXtra mov's based on $rem */
|
||||
uint32_t dst : 5;
|
||||
uint32_t src2 : 5;
|
||||
uint32_t src1 : 5;
|
||||
|
|
|
|||
|
|
@ -170,6 +170,10 @@ static void emit_instructions(int outfd)
|
|||
if (ai->has_immed) {
|
||||
/* MSB overlaps with STORE */
|
||||
assert(ai->tok != T_OP_MSB);
|
||||
if (ai->xmov) {
|
||||
fprintf(stderr, "ALU instruction cannot have immediate and xmov\n");
|
||||
exit(1);
|
||||
}
|
||||
opc = tok2alu(ai->tok);
|
||||
instr.alui.dst = ai->dst;
|
||||
instr.alui.src = ai->src1;
|
||||
|
|
@ -179,6 +183,7 @@ static void emit_instructions(int outfd)
|
|||
instr.alu.dst = ai->dst;
|
||||
instr.alu.src1 = ai->src1;
|
||||
instr.alu.src2 = ai->src2;
|
||||
instr.alu.xmov = ai->xmov;
|
||||
instr.alu.alu = tok2alu(ai->tok);
|
||||
}
|
||||
break;
|
||||
|
|
@ -186,6 +191,10 @@ static void emit_instructions(int outfd)
|
|||
/* move can either be encoded as movi (ie. move w/ immed) or
|
||||
* an alu instruction
|
||||
*/
|
||||
if ((ai->has_immed || ai->label) && ai->xmov) {
|
||||
fprintf(stderr, "ALU instruction cannot have immediate and xmov\n");
|
||||
exit(1);
|
||||
}
|
||||
if (ai->has_immed) {
|
||||
opc = OPC_MOVI;
|
||||
instr.movi.dst = ai->dst;
|
||||
|
|
@ -206,6 +215,7 @@ static void emit_instructions(int outfd)
|
|||
instr.alu.dst = ai->dst;
|
||||
instr.alu.src1 = 0x00; /* $00 reads-back 0 */
|
||||
instr.alu.src2 = ai->src1;
|
||||
instr.alu.xmov = ai->xmov;
|
||||
instr.alu.alu = OPC_OR;
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ struct asm_instruction {
|
|||
int immed;
|
||||
int shift;
|
||||
int bit;
|
||||
int xmov;
|
||||
uint32_t literal;
|
||||
const char *label;
|
||||
|
||||
|
|
|
|||
|
|
@ -506,6 +506,8 @@ static void disasm(uint32_t *buf, int sizedwords)
|
|||
|
||||
if (rep)
|
||||
printf("(rep)");
|
||||
if (instr->alu.xmov)
|
||||
printf("(xmov%d)", instr->alu.xmov);
|
||||
|
||||
/* special case mnemonics:
|
||||
* reading $00 seems to always yield zero, and so:
|
||||
|
|
@ -531,10 +533,58 @@ static void disasm(uint32_t *buf, int sizedwords)
|
|||
/* print out unexpected bits: */
|
||||
if (verbose) {
|
||||
if (instr->alu.pad)
|
||||
printerr(" (pad=%03x)", instr->alu.pad);
|
||||
printerr(" (pad=%01x)", instr->alu.pad);
|
||||
if (instr->alu.src1 && !src1)
|
||||
printerr(" (src1=%02x)", instr->alu.src1);
|
||||
}
|
||||
|
||||
/* xmov is a modifier that makes the processor execute up to 3
|
||||
* extra mov's after the current instruction. Given an ALU
|
||||
* instruction:
|
||||
*
|
||||
* (xmovN) alu $dst, $src1, $src2
|
||||
*
|
||||
* In all of the uses in the firmware blob, $dst and $src2 are one
|
||||
* of the "special" registers $data, $addr, $addr2. I've observed
|
||||
* that if $dst isn't "special" then it's replaced with $00
|
||||
* instead of $data, but I haven't checked what happens if $src2
|
||||
* isn't "special". Anyway, in the usual case, the HW produces a
|
||||
* count M = min(N, $rem) and then does the following:
|
||||
*
|
||||
* M = 1:
|
||||
* mov $data, $src2
|
||||
*
|
||||
* M = 2:
|
||||
* mov $data, $src2
|
||||
* mov $data, $src2
|
||||
*
|
||||
* M = 3:
|
||||
* mov $data, $src2
|
||||
* mov $dst, $src2 (special case for CP_CONTEXT_REG_BUNCH)
|
||||
* mov $data, $src2
|
||||
*
|
||||
* It seems to be frequently used in combination with (rep) to
|
||||
* provide a kind of hardware-based loop unrolling, and there's
|
||||
* even a special case in the ISA to be able to do this with
|
||||
* CP_CONTEXT_REG_BUNCH. However (rep) isn't required.
|
||||
*
|
||||
* This dumps the expected extra instructions, assuming that $rem
|
||||
* isn't too small.
|
||||
*/
|
||||
if (verbose && instr->alu.xmov) {
|
||||
for (int i = 0; i < instr->alu.xmov; i++) {
|
||||
printf("\n ; mov ");
|
||||
if (instr->alu.dst < 0x1d)
|
||||
printf("$00");
|
||||
else if (instr->alu.xmov == 3 && i == 1)
|
||||
print_dst(instr->alu.dst);
|
||||
else
|
||||
printf("$data");
|
||||
printf(", ");
|
||||
print_src(instr->alu.src2);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case OPC_CWRITE6:
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@ extern YYSTYPE yylval;
|
|||
"setsecure" return TOKEN(T_OP_SETSECURE);
|
||||
"<<" return TOKEN(T_LSHIFT);
|
||||
"(rep)" return TOKEN(T_REP);
|
||||
"(xmov"[1-3]")" yylval.num = yytext[5] - '\0'; return T_XMOV;
|
||||
|
||||
"," return ',';
|
||||
"[" return '[';
|
||||
|
|
|
|||
|
|
@ -161,6 +161,7 @@ label(const char *str)
|
|||
%token <tok> T_OP_SETSECURE
|
||||
%token <tok> T_LSHIFT
|
||||
%token <tok> T_REP
|
||||
%token <num> T_XMOV
|
||||
|
||||
%type <num> reg
|
||||
%type <num> immediate
|
||||
|
|
@ -182,6 +183,7 @@ instr_or_label: instr_r
|
|||
|
||||
/* instructions that can optionally have (rep) flag: */
|
||||
instr_r: alu_instr
|
||||
| T_XMOV alu_instr { instr->xmov = $1; }
|
||||
| config_instr
|
||||
|
||||
/* need to special case:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue