summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Clark <robdclark@gmail.com>2015-04-18 13:36:06 -0400
committerRob Clark <robdclark@gmail.com>2015-04-18 13:49:35 -0400
commit0ab745edfc9e06aa67db13dcddba2ec24839cc83 (patch)
tree5c8525afad5c66eb4453afa90fdaa6aa68b52d22
parent01f3dd2168fc9161cc59af8a2d04076639274b65 (diff)
ir3emu: initial cat6 support (ldg)
-rw-r--r--asm/ir-a3xx.c62
-rw-r--r--asm/parser.y11
-rw-r--r--instr-a3xx.h46
-rw-r--r--ir3emu.c39
4 files changed, 92 insertions, 66 deletions
diff --git a/asm/ir-a3xx.c b/asm/ir-a3xx.c
index 9f64b0a..42821d4 100644
--- a/asm/ir-a3xx.c
+++ b/asm/ir-a3xx.c
@@ -454,58 +454,40 @@ static int emit_cat5(struct ir3_instruction *instr, void *ptr,
static int emit_cat6(struct ir3_instruction *instr, void *ptr,
struct ir3_shader_info *info)
{
- struct ir3_register *dst = instr->regs[0];
- struct ir3_register *src = instr->regs[1];
+ struct ir3_register *dst = instr->regs[0];
+ struct ir3_register *src1 = instr->regs[1];
+ struct ir3_register *src2 = (instr->regs_count >= 3) ? instr->regs[2] : NULL;
instr_cat6_t *cat6 = ptr;
- iassert(instr->regs_count == 2);
+ iassert(instr->regs_count >= 2);
- switch (instr->opc) {
- /* load instructions: */
- case OPC_LDG:
- case OPC_LDP:
- case OPC_LDL:
- case OPC_LDLW:
- case OPC_LDLV:
- case OPC_PREFETCH: {
+ if (instr->cat6.offset || instr->opc == OPC_LDG) {
instr_cat6a_t *cat6a = ptr;
- iassert(!((dst->flags ^ type_flags(instr->cat6.type)) & IR3_REG_HALF));
+ cat6->has_off = true;
- cat6a->must_be_one1 = 1;
- cat6a->must_be_one2 = 1;
- cat6a->off = instr->cat6.offset;
- cat6a->src = reg(src, info, instr->repeat, 0);
cat6a->dst = reg(dst, info, instr->repeat, IR3_REG_R | IR3_REG_HALF);
- break;
- }
- /* store instructions: */
- case OPC_STG:
- case OPC_STP:
- case OPC_STL:
- case OPC_STLW:
- case OPC_STI: {
+ cat6a->src1 = reg(src1, info, instr->repeat, IR3_REG_IMMED);
+ cat6a->src1_im = !!(src1->flags & IR3_REG_IMMED);
+ if (src2) {
+ cat6a->src2 = reg(src2, info, instr->repeat, IR3_REG_IMMED);
+ cat6a->src2_im = !!(src2->flags & IR3_REG_IMMED);
+ }
+ cat6a->off = instr->cat6.offset;
+ } else {
instr_cat6b_t *cat6b = ptr;
- uint32_t src_flags = type_flags(instr->cat6.type);
- uint32_t dst_flags = (instr->opc == OPC_STI) ? IR3_REG_HALF : 0;
-
- iassert(!((src->flags ^ src_flags) & IR3_REG_HALF));
- cat6b->must_be_one1 = 1;
- cat6b->must_be_one2 = 1;
- cat6b->src = reg(src, info, instr->repeat, src_flags);
- cat6b->off_hi = instr->cat6.offset >> 8;
- cat6b->off = instr->cat6.offset;
- cat6b->dst = reg(dst, info, instr->repeat, IR3_REG_R | dst_flags);
+ cat6->has_off = false;
- break;
- }
- default:
- // TODO
- break;
+ cat6b->dst = reg(dst, info, instr->repeat, IR3_REG_R | IR3_REG_HALF);
+ cat6b->src1 = reg(src1, info, instr->repeat, IR3_REG_IMMED);
+ cat6b->src1_im = !!(src1->flags & IR3_REG_IMMED);
+ if (src2) {
+ cat6b->src2 = reg(src2, info, instr->repeat, IR3_REG_IMMED);
+ cat6b->src2_im = !!(src2->flags & IR3_REG_IMMED);
+ }
}
- cat6->iim_val = instr->cat6.iim_val;
cat6->type = instr->cat6.type;
cat6->opc = instr->opc;
cat6->jmp_tgt = !!(instr->flags & IR3_INSTR_JP);
diff --git a/asm/parser.y b/asm/parser.y
index 48661d6..d5f9bde 100644
--- a/asm/parser.y
+++ b/asm/parser.y
@@ -619,11 +619,11 @@ cat6_type: '.' type { instr->cat6.type = $2; }
cat6_offset: offset { instr->cat6.offset = $1; }
cat6_immed: integer { instr->cat6.iim_val = $1; }
-cat6_load: T_OP_LDG { new_instr(6, OPC_LDG); } cat6_type dst_reg ',' 'g' '[' reg cat6_offset ']' ',' cat6_immed
-| T_OP_LDP { new_instr(6, OPC_LDP); } cat6_type dst_reg ',' 'p' '[' reg cat6_offset ']' ',' cat6_immed
-| T_OP_LDL { new_instr(6, OPC_LDL); } cat6_type dst_reg ',' 'l' '[' reg cat6_offset ']' ',' cat6_immed
-| T_OP_LDLW { new_instr(6, OPC_LDLW); } cat6_type dst_reg ',' 'l' '[' reg cat6_offset ']' ',' cat6_immed
-| T_OP_LDLV { new_instr(6, OPC_LDLV); } cat6_type dst_reg ',' 'l' '[' reg cat6_offset ']' ',' cat6_immed
+cat6_load: T_OP_LDG { new_instr(6, OPC_LDG); } cat6_type dst_reg ',' 'g' '[' reg cat6_offset ']' ',' reg
+| T_OP_LDP { new_instr(6, OPC_LDP); } cat6_type dst_reg ',' 'p' '[' reg cat6_offset ']' ',' reg
+| T_OP_LDL { new_instr(6, OPC_LDL); } cat6_type dst_reg ',' 'l' '[' reg cat6_offset ']' ',' reg
+| T_OP_LDLW { new_instr(6, OPC_LDLW); } cat6_type dst_reg ',' 'l' '[' reg cat6_offset ']' ',' reg
+| T_OP_LDLV { new_instr(6, OPC_LDLV); } cat6_type dst_reg ',' 'l' '[' reg cat6_offset ']' ',' reg
cat6_store: T_OP_STG { new_instr(6, OPC_STG); } cat6_type 'g' '[' dst_reg cat6_offset ']' ',' reg ',' cat6_immed
| T_OP_STP { new_instr(6, OPC_STP); } cat6_type 'p' '[' dst_reg cat6_offset ']' ',' reg ',' cat6_immed
@@ -667,6 +667,7 @@ cat6_instr: cat6_load
reg: T_REGISTER { $$ = new_reg($1, 0); }
| T_A0 { $$ = new_reg((61 << 3) + $1, IR3_REG_HALF); }
| T_P0 { $$ = new_reg((62 << 3) + $1, 0); }
+| T_INT { $$ = new_reg(0, IR3_REG_IMMED); $$->iim_val = $1; }
const: T_CONSTANT { $$ = new_reg($1, IR3_REG_CONST); }
diff --git a/instr-a3xx.h b/instr-a3xx.h
index a524b61..f931168 100644
--- a/instr-a3xx.h
+++ b/instr-a3xx.h
@@ -322,6 +322,7 @@ typedef struct PACKED {
};
/* for immediate: */
int32_t iim_val;
+ uint32_t uim_val;
float fim_val;
};
@@ -573,15 +574,15 @@ typedef struct PACKED {
uint32_t opc_cat : 3;
} instr_cat5_t;
-/* used for load instructions: */
+/* [src1 + off], src2: */
typedef struct PACKED {
/* dword0: */
- uint32_t must_be_one1 : 1;
- int16_t off : 13;
- uint32_t src : 8;
- uint32_t dummy1 : 1;
- uint32_t must_be_one2 : 1;
- int32_t iim_val : 8;
+ uint32_t mustbe1 : 1;
+ int32_t off : 13;
+ uint32_t src1 : 8;
+ uint32_t src1_im : 1;
+ uint32_t src2_im : 1;
+ uint32_t src2 : 8;
/* dword1: */
uint32_t dst : 8;
@@ -594,40 +595,43 @@ typedef struct PACKED {
uint32_t opc_cat : 3;
} instr_cat6a_t;
-/* used for store instructions: */
+/* [src1], src2: */
typedef struct PACKED {
/* dword0: */
- uint32_t must_be_zero1 : 1;
- uint32_t src : 8;
- uint32_t off_hi : 5; /* high bits of 'off'... ugly! */
- uint32_t dummy1 : 9;
- uint32_t must_be_one1 : 1;
- int32_t iim_val : 8;
+ uint32_t mustbe0 : 1;
+ uint32_t src1 : 8;
+ uint32_t ignore0 : 13;
+ uint32_t src1_im : 1;
+ uint32_t src2_im : 1;
+ uint32_t src2 : 8;
/* dword1: */
- uint16_t off : 8;
- uint32_t must_be_one2 : 1;
uint32_t dst : 8;
+ uint32_t dummy2 : 9;
uint32_t type : 3;
- uint32_t dummy2 : 2;
+ uint32_t dummy3 : 2;
uint32_t opc : 5;
uint32_t jmp_tgt : 1;
uint32_t sync : 1;
uint32_t opc_cat : 3;
} instr_cat6b_t;
+/* I think some of the other cat6 instructions use additional
+ * sub-encodings..
+ */
typedef union PACKED {
instr_cat6a_t a;
instr_cat6b_t b;
struct PACKED {
/* dword0: */
- uint32_t pad1 : 24;
- int32_t iim_val : 8;
+ uint32_t has_off : 1;
+ uint32_t pad1 : 31;
/* dword1: */
- uint32_t pad2 : 17;
+ uint32_t dst : 8;
+ uint32_t dummy2 : 9;
uint32_t type : 3;
- uint32_t pad3 : 2;
+ uint32_t dummy3 : 2;
uint32_t opc : 5;
uint32_t jmp_tgt : 1;
uint32_t sync : 1;
diff --git a/ir3emu.c b/ir3emu.c
index c5bacfc..18ea19e 100644
--- a/ir3emu.c
+++ b/ir3emu.c
@@ -835,6 +835,44 @@ emu_run_cat5(struct ir3_emu_ctx *ctx, instr_cat5_t *cat5)
}
}
+
+static void
+emu_run_cat6(struct ir3_emu_ctx *ctx, instr_cat6_t *cat6)
+{
+ regval_t dst, src1, src2;
+ unsigned offset = 0;
+
+ if (cat6->has_off) {
+ src1 = read_src(ctx, 0, (struct ir3_regsrc){
+ .src = (reg_t)cat6->a.src1,
+ .full = true,
+ .im = cat6->a.src1_im,
+ });
+ src2 = read_src(ctx, 0, (struct ir3_regsrc){
+ .src = (reg_t)cat6->a.src2,
+ .full = true,
+ .im = cat6->a.src2_im,
+ });
+ offset = cat6->a.off;
+ } else {
+ // TODO
+ }
+
+ switch (cat6->opc) {
+ case OPC_LDG:
+ dst.u = src1.u + offset + src2.u;
+ break;
+ default:
+ emu_fatal(ctx, "unhandled cat6 opc: %u", cat6->opc);
+ break;
+ }
+
+ write_dst(ctx, dst, (struct ir3_regdst){
+ .dst = (reg_t)(cat6->dst),
+ .full = (type_size(cat6->type) == 32),
+ });
+}
+
static void
emu_run(struct ir3_emu_ctx *ctx)
{
@@ -889,6 +927,7 @@ emu_run(struct ir3_emu_ctx *ctx)
case 3: emu_run_cat3(ctx, &instr->cat3); break;
case 4: emu_run_cat4(ctx, &instr->cat4); break;
case 5: emu_run_cat5(ctx, &instr->cat5); break;
+ case 6: emu_run_cat6(ctx, &instr->cat6); break;
default:
emu_fatal(ctx, "unhandled instruction category: %d", instr->opc_cat);
break;