assert(i->rnd == ROUND_N);
assert(!i->saturate);
- emitForm_L(i, 0x400, 0, i->src(1).mod);
+ Modifier mod = i->src(1).mod ^
+ Modifier(i->op == OP_SUB ? NV50_IR_MOD_NEG : 0);
+
+ emitForm_L(i, 0x400, 0, mod);
FTZ_(3a);
NEG_(3b, 0);
if (code[0] & 0x1) {
modNegAbsF32_3b(i, 1);
+ if (i->op == OP_SUB) code[1] ^= 1 << 27;
} else {
ABS_(34, 1);
NEG_(30, 1);
+ if (i->op == OP_SUB) code[1] ^= 1 << 16;
}
}
}
void
CodeEmitterGK110::emitShift(const Instruction *i)
{
- const bool sar = i->op == OP_SHR && isSignedType(i->sType);
-
- if (sar) {
- emitForm_21(i, 0x214, 0x014);
- code[1] |= 1 << 19;
- } else
if (i->op == OP_SHR) {
- // this is actually RSHF
- emitForm_21(i, 0x27c, 0x87c);
- code[1] |= GK110_GPR_ZERO << 10;
+ emitForm_21(i, 0x214, 0xc14);
+ if (isSignedType(i->dType))
+ code[1] |= 1 << 19;
} else {
- // this is actually LSHF
- emitForm_21(i, 0x1fc, 0xb7c);
- code[1] |= GK110_GPR_ZERO << 10;
+ emitForm_21(i, 0x224, 0xc24);
}
- if (i->subOp == NV50_IR_SUBOP_SHIFT_WRAP) {
- if (!sar)
- code[1] |= 1 << 21;
- // XXX: find wrap modifier for SHR S32
- }
+ if (i->subOp == NV50_IR_SUBOP_SHIFT_WRAP)
+ code[1] |= 1 << 10;
}
void
CodeEmitterGK110::emitPreOp(const Instruction *i)
{
- emitForm_21(i, 0x248, -1);
+ emitForm_C(i, 0x248, 0x2);
if (i->op == OP_PREEX2)
code[1] |= 1 << 10;
void CodeEmitterGK110::emitTEXCSAA(const TexInstruction *i)
{
- emitNOP(i); // TODO
+ code[0] = 0x00000002;
+ code[1] = 0x76c00000;
+
+ code[1] |= i->tex.r << 9;
+ // code[1] |= i->tex.s << (9 + 8);
+
+ if (i->tex.liveOnly)
+ code[0] |= 0x80000000;
+
+ defId(i->def(0), 2);
+ srcId(i->src(0), 10);
}
static inline bool
case OP_TXD:
code[1] = 0x7e000000;
break;
+ case OP_TXF:
+ code[1] = 0x78000000;
+ break;
default:
code[1] = 0x7d800000;
break;
case OP_TXD:
code[0] = 0x00000002;
code[1] = 0x76000000;
+ code[1] |= i->tex.r << 9;
+ break;
+ case OP_TXF:
+ code[0] = 0x00000002;
+ code[1] = 0x70000000;
+ code[1] |= i->tex.r << 13;
break;
default:
code[0] = 0x00000001;
code[1] = 0x60000000;
+ code[1] |= i->tex.r << 15;
break;
}
- code[1] |= i->tex.r << 15;
}
code[1] |= isNextIndependentTex(i) ? 0x1 : 0x2; // t : p mode
- // if (i->tex.liveOnly)
- // ?
+ if (i->tex.liveOnly)
+ code[0] |= 0x80000000;
switch (i->op) {
case OP_TEX: break;
case OP_TXB: code[1] |= 0x2000; break;
case OP_TXL: code[1] |= 0x3000; break;
- case OP_TXF: break; // XXX
+ case OP_TXF: break;
case OP_TXG: break; // XXX
case OP_TXD: break;
default:
assert(!"invalid texture op");
break;
}
- /*
+
if (i->op == OP_TXF) {
if (!i->tex.levelZero)
- code[1] |= 0x02000000;
- } else */
+ code[1] |= 0x1000;
+ } else
if (i->tex.levelZero) {
code[1] |= 0x1000;
}
- // if (i->op != OP_TXD && i->tex.derivAll)
- // code[1] |= 1 << 13;
+ if (i->op != OP_TXD && i->tex.derivAll)
+ code[1] |= 0x200;
emitPredicate(i);
code[1] |= (i->tex.target.isCube() ? 3 : (i->tex.target.getDim() - 1)) << 7;
if (i->tex.target.isArray())
code[1] |= 0x40;
- // if (i->tex.target.isShadow())
- // ?
- // if (i->tex.target == TEX_TARGET_2D_MS ||
- // i->tex.target == TEX_TARGET_2D_MS_ARRAY)
- // ?
+ if (i->tex.target.isShadow())
+ code[1] |= 0x400;
+ if (i->tex.target == TEX_TARGET_2D_MS ||
+ i->tex.target == TEX_TARGET_2D_MS_ARRAY)
+ code[1] |= 0x800;
if (i->srcExists(src1) && i->src(src1).getFile() == FILE_IMMEDIATE) {
// ?
}
- // if (i->tex.useOffsets)
- // ?
+ if (i->tex.useOffsets) {
+ switch (i->op) {
+ case OP_TXF: code[1] |= 0x200; break;
+ default: code[1] |= 0x800; break;
+ }
+ }
}
void
CodeEmitterGK110::emitTXQ(const TexInstruction *i)
{
- emitNOP(i); // TODO
+ code[0] = 0x00000002;
+ code[1] = 0x75400001;
+
+ switch (i->tex.query) {
+ case TXQ_DIMS: code[0] |= 0x01 << 25; break;
+ case TXQ_TYPE: code[0] |= 0x02 << 25; break;
+ case TXQ_SAMPLE_POSITION: code[0] |= 0x05 << 25; break;
+ case TXQ_FILTER: code[0] |= 0x10 << 25; break;
+ case TXQ_LOD: code[0] |= 0x12 << 25; break;
+ case TXQ_BORDER_COLOUR: code[0] |= 0x16 << 25; break;
+ default:
+ assert(!"invalid texture query");
+ break;
+ }
+
+ code[1] |= i->tex.mask << 2;
+ code[1] |= i->tex.r << 9;
+ if (/*i->tex.sIndirectSrc >= 0 || */i->tex.rIndirectSrc >= 0)
+ code[1] |= 0x08000000;
+
+ defId(i->def(0), 2);
+ srcId(i->src(0), 10);
+
+ emitPredicate(i);
}
void
CodeEmitterGK110::emitQUADOP(const Instruction *i, uint8_t qOp, uint8_t laneMask)
{
- emitNOP(i); // TODO
+ code[0] = 0x00000002 | ((qOp & 1) << 31);
+ code[1] = 0x7fc00000 | (qOp >> 1) | (laneMask << 12);
+
+ defId(i->def(0), 2);
+ srcId(i->src(0), 10);
+ srcId(i->srcExists(1) ? i->src(1) : i->src(0), 23);
+
+ if (i->op == OP_QUADOP && progType != Program::TYPE_FRAGMENT)
+ code[1] |= 1 << 9; // dall
+
+ emitPredicate(i);
}
void
void
CodeEmitterGK110::emitPFETCH(const Instruction *i)
{
- emitNOP(i); // TODO
+ uint32_t prim = i->src(0).get()->reg.data.u32;
+
+ code[0] = 0x00000002 | ((prim & 0xff) << 23);
+ code[1] = 0x7f800000;
+
+ emitPredicate(i);
+
+ defId(i->def(0), 2);
+ srcId(i->src(1), 10);
}
void
CodeEmitterGK110::emitVFETCH(const Instruction *i)
{
+ unsigned int size = typeSizeof(i->dType);
uint32_t offset = i->src(0).get()->reg.data.offset;
code[0] = 0x00000002 | (offset << 23);
code[1] = 0x7ec00000 | (offset >> 9);
+ code[1] |= (size / 4 - 1) << 18;
#if 0
if (i->perPatch)
void
CodeEmitterGK110::emitEXPORT(const Instruction *i)
{
+ unsigned int size = typeSizeof(i->dType);
uint32_t offset = i->src(0).get()->reg.data.offset;
code[0] = 0x00000002 | (offset << 23);
code[1] = 0x7f000000 | (offset >> 9);
+ code[1] |= (size / 4 - 1) << 18;
#if 0
if (i->perPatch)
void
CodeEmitterGK110::emitOUT(const Instruction *i)
{
- emitNOP(i); // TODO
+ assert(i->src(0).getFile() == FILE_GPR);
+
+ emitForm_21(i, 0x1f0, 0xb70);
+
+ if (i->op == OP_EMIT)
+ code[1] |= 1 << 10;
+ if (i->op == OP_RESTART || i->subOp == NV50_IR_SUBOP_EMIT_RESTART)
+ code[1] |= 1 << 11;
}
void
setImmediate32(i, 0, Modifier(0));
} else
if (i->src(0).getFile() == FILE_PREDICATE) {
- // TODO
+ code[0] = 0x00000002;
+ code[1] = 0x84401c07;
+ emitPredicate(i);
+ defId(i->def(0), 2);
+ srcId(i->src(0), 14);
} else {
emitForm_C(i, 0x24c, 2);
code[1] |= i->lanes << 10;
case 1: data[0] |= insn->sched << 10; break;
case 2: data[0] |= insn->sched << 18; break;
case 3: data[0] |= insn->sched << 26; data[1] |= insn->sched >> 6; break;
- case 4: data[1] |= insn->sched << 2;
+ case 4: data[1] |= insn->sched << 2; break;
case 5: data[1] |= insn->sched << 10; break;
case 6: data[1] |= insn->sched << 18; break;
default: