diff options
author | Rob Clark <robdclark@gmail.com> | 2015-04-18 13:36:06 -0400 |
---|---|---|
committer | Rob Clark <robdclark@gmail.com> | 2015-04-18 13:49:35 -0400 |
commit | 0ab745edfc9e06aa67db13dcddba2ec24839cc83 (patch) | |
tree | 5c8525afad5c66eb4453afa90fdaa6aa68b52d22 | |
parent | 01f3dd2168fc9161cc59af8a2d04076639274b65 (diff) |
ir3emu: initial cat6 support (ldg)
-rw-r--r-- | asm/ir-a3xx.c | 62 | ||||
-rw-r--r-- | asm/parser.y | 11 | ||||
-rw-r--r-- | instr-a3xx.h | 46 | ||||
-rw-r--r-- | ir3emu.c | 39 |
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; @@ -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; |