summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Clark <robdclark@gmail.com>2015-04-04 09:20:55 -0400
committerRob Clark <robdclark@gmail.com>2015-04-04 09:20:55 -0400
commit01f3dd2168fc9161cc59af8a2d04076639274b65 (patch)
tree4613d2799d34401762bf5777840619c66b7ccb99
parent954092869f4c4224c999193ea1a37c2817063d97 (diff)
ir3emu: some fixes
-rw-r--r--ir3emu.c87
1 files changed, 55 insertions, 32 deletions
diff --git a/ir3emu.c b/ir3emu.c
index 2319714..c5bacfc 100644
--- a/ir3emu.c
+++ b/ir3emu.c
@@ -365,26 +365,22 @@ emu_run_cat1(struct ir3_emu_ctx *ctx, instr_cat1_t *cat1)
});
}
- if (type_float(cat1->src_type) &&
- type_uint(cat1->dst_type)) {
+ if (type_float(cat1->src_type) && type_uint(cat1->dst_type)) {
dst.u = src.f;
- } else if (type_float(cat1->src_type) &&
- type_sint(cat1->dst_type)) {
+ } else if (type_float(cat1->src_type) && type_sint(cat1->dst_type)) {
dst.i = src.f;
- } else if (type_uint(cat1->src_type) &&
- type_sint(cat1->dst_type)) {
+ } else if (type_uint(cat1->src_type) && type_sint(cat1->dst_type)) {
dst.i = src.u;
- } else if (type_uint(cat1->src_type) &&
- type_float(cat1->dst_type)) {
- dst.i = src.f;
- } else if (type_sint(cat1->src_type) &&
- type_float(cat1->dst_type)) {
- dst.f = src.i;
- } else if (type_sint(cat1->src_type) &&
- type_uint(cat1->dst_type)) {
+ } else if (type_uint(cat1->src_type) && type_float(cat1->dst_type)) {
dst.f = src.u;
+ } else if (type_sint(cat1->src_type) && type_float(cat1->dst_type)) {
+ dst.f = src.i;
+ } else if (type_sint(cat1->src_type) && type_uint(cat1->dst_type)) {
+ dst.u = src.i;
+ } else if (cat1->src_type == cat1->dst_type) {
+ dst.u = src.u;
} else {
- dst.f = src.f;
+ assert(0);
}
write_dst(ctx, dst, (struct ir3_regdst){
@@ -399,6 +395,19 @@ emu_run_cat2(struct ir3_emu_ctx *ctx, instr_cat2_t *cat2)
{
struct ir3_regsrc src2rs;
regval_t dst, src1, src2;
+ bool absnegf;
+
+ switch (cat2->opc) {
+ /* TODO the .b instructions do bitwise negate, rather than
+ * float abs/neg, so they also need special handling..
+ */
+ case OPC_ABSNEG_S:
+ absnegf = false;
+ break;
+ default:
+ absnegf = true;
+ break;
+ }
if (cat2->c1.src1_c) {
src1 = read_src(ctx, 0, (struct ir3_regsrc){
@@ -407,8 +416,8 @@ emu_run_cat2(struct ir3_emu_ctx *ctx, instr_cat2_t *cat2)
.r = cat2->src1_r,
.c = cat2->c1.src1_c,
.im = cat2->src1_im,
- .neg = cat2->src1_neg,
- .abs = cat2->src1_abs,
+ .neg = cat2->src1_neg && absnegf,
+ .abs = cat2->src1_abs && absnegf,
});
} else if (cat2->rel1.src1_rel) {
src1 = read_src(ctx, 0, (struct ir3_regsrc){
@@ -417,8 +426,8 @@ emu_run_cat2(struct ir3_emu_ctx *ctx, instr_cat2_t *cat2)
.r = cat2->src1_r,
.c = cat2->rel1.src1_c,
.im = cat2->src1_im,
- .neg = cat2->src1_neg,
- .abs = cat2->src1_abs,
+ .neg = cat2->src1_neg && absnegf,
+ .abs = cat2->src1_abs && absnegf,
.rel = cat2->rel1.src1_rel,
});
} else {
@@ -427,8 +436,8 @@ emu_run_cat2(struct ir3_emu_ctx *ctx, instr_cat2_t *cat2)
.full = cat2->full,
.r = cat2->src1_r,
.im = cat2->src1_im,
- .neg = cat2->src1_neg,
- .abs = cat2->src1_abs,
+ .neg = cat2->src1_neg && absnegf,
+ .abs = cat2->src1_abs && absnegf,
});
}
@@ -439,8 +448,8 @@ emu_run_cat2(struct ir3_emu_ctx *ctx, instr_cat2_t *cat2)
.r = cat2->src2_r,
.c = cat2->c2.src2_c,
.im = cat2->src2_im,
- .neg = cat2->src2_neg,
- .abs = cat2->src2_abs,
+ .neg = cat2->src2_neg && absnegf,
+ .abs = cat2->src2_abs && absnegf,
};
} else if (cat2->rel2.src2_rel) {
src2rs = (struct ir3_regsrc){
@@ -449,8 +458,8 @@ emu_run_cat2(struct ir3_emu_ctx *ctx, instr_cat2_t *cat2)
.r = cat2->src2_r,
.c = cat2->rel2.src2_c,
.im = cat2->src2_im,
- .neg = cat2->src2_neg,
- .abs = cat2->src2_abs,
+ .neg = cat2->src2_neg && absnegf,
+ .abs = cat2->src2_abs && absnegf,
.rel = cat2->rel2.src2_rel,
};
} else {
@@ -459,8 +468,8 @@ emu_run_cat2(struct ir3_emu_ctx *ctx, instr_cat2_t *cat2)
.full = cat2->full,
.r = cat2->src2_r,
.im = cat2->src2_im,
- .neg = cat2->src2_neg,
- .abs = cat2->src2_abs,
+ .neg = cat2->src2_neg && absnegf,
+ .abs = cat2->src2_abs && absnegf,
};
}
@@ -473,6 +482,22 @@ emu_run_cat2(struct ir3_emu_ctx *ctx, instr_cat2_t *cat2)
src2 = read_src(ctx, 1, src2rs);
}
+ if (!absnegf) {
+ switch (cat2->opc) {
+ /* TODO the .b instructions do bitwise negate, rather than
+ * float abs/neg, so they also need special handling..
+ */
+ case OPC_ABSNEG_S:
+ if (cat2->src1_neg)
+ src1.i = -src1.i;
+ if (cat2->src1_abs)
+ src1.i = abs(src1.i);
+ break;
+ default:
+ break;
+ }
+ }
+
switch (cat2->opc) {
case OPC_ADD_F:
dst.f = src1.f + src2.f;
@@ -490,8 +515,7 @@ emu_run_cat2(struct ir3_emu_ctx *ctx, instr_cat2_t *cat2)
dst.i = src1.i * src2.i;
break;
case OPC_MULL_U:
- /* technically, I think, this should multiply just the low bits.. */
- dst.u = src1.u * src2.u;
+ dst.u = (src1.u & 0xffff) * (src2.u & 0xffff);
break;
case OPC_CMPS_F:
switch (cat2->cond) {
@@ -660,14 +684,13 @@ emu_run_cat3(struct ir3_emu_ctx *ctx, instr_cat3_t *cat3)
dst.f = (src1.f * src2.f) + src3.f;
break;
case OPC_MADSH_M16:
- /* technically this should mul-add shift high, ie. ah * bl << 16 */
- dst.u = (src1.u * src2.u) + src3.u;
+ dst.u = (((src1.u >> 16) * (src2.u & 0xffff)) << 16) + src3.u;
break;
case OPC_SEL_F32:
dst.f = (src2.i >= 0) ? src3.f : src1.f;
break;
case OPC_SEL_B32:
- dst.f = src2.u ? src3.f : src1.f;
+ dst.f = src2.u ? src1.f : src3.f;
break;
default:
emu_fatal(ctx, "unhandled cat3 opc: %u", cat3->opc);