summaryrefslogtreecommitdiff
path: root/src/gallium/drivers/nvc0/nvc0_pc_emit.c
diff options
context:
space:
mode:
authorChristoph Bumiller <e0425955@student.tuwien.ac.at>2010-11-12 15:17:40 +0100
committerChristoph Bumiller <e0425955@student.tuwien.ac.at>2010-11-12 15:17:40 +0100
commit4c2247538394a313e1e90bfcd07c1ab9c7d41281 (patch)
treeedbf5d81cace64f63fd8361df4cf94b5b7ded43b /src/gallium/drivers/nvc0/nvc0_pc_emit.c
parent93edd15178a4d3367ac3d2f9369603807de411d7 (diff)
nvc0: import nvc0 gallium driver
Diffstat (limited to 'src/gallium/drivers/nvc0/nvc0_pc_emit.c')
-rw-r--r--src/gallium/drivers/nvc0/nvc0_pc_emit.c943
1 files changed, 943 insertions, 0 deletions
diff --git a/src/gallium/drivers/nvc0/nvc0_pc_emit.c b/src/gallium/drivers/nvc0/nvc0_pc_emit.c
new file mode 100644
index 0000000000..8a94175e27
--- /dev/null
+++ b/src/gallium/drivers/nvc0/nvc0_pc_emit.c
@@ -0,0 +1,943 @@
+/*
+ * Copyright 2010 Christoph Bumiller
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "nvc0_pc.h"
+#include "nvc0_program.h"
+
+#define NVC0_FIXUP_CODE_RELOC 0
+#define NVC0_FIXUP_DATA_RELOC 1
+
+struct nvc0_fixup {
+ uint8_t type;
+ int8_t shift;
+ uint32_t mask;
+ uint32_t data;
+ uint32_t ofst;
+};
+
+void
+nvc0_relocate_program(struct nvc0_program *prog,
+ uint32_t code_base,
+ uint32_t data_base)
+{
+ struct nvc0_fixup *f = (struct nvc0_fixup *)prog->relocs;
+ unsigned i;
+
+ for (i = 0; i < prog->num_relocs; ++i) {
+ uint32_t data;
+
+ switch (f[i].type) {
+ case NVC0_FIXUP_CODE_RELOC: data = code_base + f[i].data; break;
+ case NVC0_FIXUP_DATA_RELOC: data = data_base + f[i].data; break;
+ default:
+ data = f[i].data;
+ break;
+ }
+ data = (f[i].shift < 0) ? (data >> -f[i].shift) : (data << f[i].shift);
+
+ prog->code[f[i].ofst / 4] &= ~f[i].mask;
+ prog->code[f[i].ofst / 4] |= data & f[i].mask;
+ }
+}
+
+static void
+create_fixup(struct nv_pc *pc, uint8_t ty,
+ int w, uint32_t data, uint32_t m, int s)
+{
+ struct nvc0_fixup *f;
+
+ const unsigned size = sizeof(struct nvc0_fixup);
+ const unsigned n = pc->num_relocs;
+
+ if (!(n % 8))
+ pc->reloc_entries = REALLOC(pc->reloc_entries, n * size, (n + 8) * size);
+
+ f = (struct nvc0_fixup *)pc->reloc_entries;
+
+ f[n].ofst = (pc->emit_pos + w) * 4;
+ f[n].type = ty;
+ f[n].data = data;
+ f[n].mask = m;
+ f[n].shift = s;
+
+ ++pc->num_relocs;
+}
+
+static INLINE ubyte
+SSIZE(struct nv_instruction *nvi, int s)
+{
+ return nvi->src[s]->value->reg.size;
+}
+
+static INLINE ubyte
+DSIZE(struct nv_instruction *nvi, int d)
+{
+ return nvi->def[d]->reg.size;
+}
+
+static INLINE struct nv_reg *
+SREG(struct nv_ref *ref)
+{
+ if (!ref)
+ return NULL;
+ return &ref->value->join->reg;
+}
+
+static INLINE struct nv_reg *
+DREG(struct nv_value *val)
+{
+ if (!val)
+ return NULL;
+ return &val->join->reg;
+}
+
+static INLINE ubyte
+SFILE(struct nv_instruction *nvi, int s)
+{
+ return nvi->src[s]->value->reg.file;
+}
+
+static INLINE ubyte
+DFILE(struct nv_instruction *nvi, int d)
+{
+ return nvi->def[0]->reg.file;
+}
+
+static INLINE void
+SID(struct nv_pc *pc, struct nv_ref *ref, int pos)
+{
+ pc->emit[pos / 32] |= (SREG(ref) ? SREG(ref)->id : 63) << (pos % 32);
+}
+
+static INLINE void
+DID(struct nv_pc *pc, struct nv_value *val, int pos)
+{
+ pc->emit[pos / 32] |= (DREG(val) ? DREG(val)->id : 63) << (pos % 32);
+}
+
+static INLINE uint32_t
+get_immd_u32(struct nv_ref *ref) /* XXX: dependent on [0]:2 */
+{
+ assert(ref->value->reg.file == NV_FILE_IMM);
+ return ref->value->reg.imm.u32;
+}
+
+static INLINE void
+set_immd_u32_l(struct nv_pc *pc, uint32_t u32)
+{
+ pc->emit[0] |= (u32 & 0x3f) << 26;
+ pc->emit[1] |= u32 >> 6;
+}
+
+static INLINE void
+set_immd_u32(struct nv_pc *pc, uint32_t u32)
+{
+ if ((pc->emit[0] & 0xf) == 0x2) {
+ set_immd_u32_l(pc, u32);
+ } else {
+ assert(!(pc->emit[1] & 0xc000));
+ pc->emit[1] |= 0xc000;
+
+ assert(!(u32 & 0xfff));
+ set_immd_u32_l(pc, u32 >> 12);
+ }
+}
+
+static INLINE void
+set_immd(struct nv_pc *pc, struct nv_instruction *i, int s)
+{
+ set_immd_u32(pc, get_immd_u32(i->src[s]));
+}
+
+static INLINE void
+DVS(struct nv_pc *pc, struct nv_instruction *i)
+{
+ uint s = i->def[0]->reg.size;
+ int n;
+ for (n = 1; n < 4 && i->def[n]; ++n)
+ s += i->def[n]->reg.size;
+ pc->emit[0] |= ((s / 4) - 1) << 5;
+}
+
+static INLINE void
+SVS(struct nv_pc *pc, struct nv_ref *src)
+{
+ pc->emit[0] |= (SREG(src)->size / 4 - 1) << 5;
+}
+
+static void
+set_pred(struct nv_pc *pc, struct nv_instruction *i)
+{
+ if (i->predicate >= 0) {
+ SID(pc, i->src[i->predicate], 6);
+ if (i->cc)
+ pc->emit[0] |= 0x2000; /* negate */
+ } else {
+ pc->emit[0] |= 0x1c00;
+ }
+}
+
+static INLINE void
+set_address_16(struct nv_pc *pc, struct nv_ref *src)
+{
+ pc->emit[0] |= (src->value->reg.address & 0x003f) << 26;
+ pc->emit[1] |= (src->value->reg.address & 0xffc0) >> 6;
+}
+
+static INLINE unsigned
+const_space_index(struct nv_instruction *i, int s)
+{
+ return SFILE(i, s) - NV_FILE_MEM_C(0);
+}
+
+static void
+emit_flow(struct nv_pc *pc, struct nv_instruction *i, uint8_t op)
+{
+ pc->emit[0] = 0x000001e7;
+ pc->emit[1] = op << 24;
+
+ set_pred(pc, i);
+
+ if (i->target) {
+ uint32_t pos = i->target->emit_pos;
+
+ create_fixup(pc, NVC0_FIXUP_CODE_RELOC, 0, pos, 26, 0xfc000000);
+ create_fixup(pc, NVC0_FIXUP_CODE_RELOC, 1, pos, -6, 0x0001ffff);
+
+ pc->emit[0] |= (pos & 0x3f) << 26;
+ pc->emit[1] |= (pos >> 6) & 0x1ffff;
+ }
+}
+
+/* doesn't work for vfetch, export, ld, st, mov ... */
+static void
+emit_form_0(struct nv_pc *pc, struct nv_instruction *i)
+{
+ int s;
+
+ set_pred(pc, i);
+
+ DID(pc, i->def[0], 14);
+
+ for (s = 0; s < 3 && i->src[s]; ++s) {
+ if (SFILE(i, s) >= NV_FILE_MEM_C(0) &&
+ SFILE(i, s) <= NV_FILE_MEM_C(15)) {
+ assert(!(pc->emit[1] & 0xc000));
+ assert(s <= 1);
+ pc->emit[1] |= 0x4000 | (const_space_index(i, s) << 10);
+ set_address_16(pc, i->src[s]);
+ } else
+ if (SFILE(i, s) == NV_FILE_GPR) {
+ SID(pc, i->src[s], s ? ((s == 2) ? 49 : 26) : 20);
+ } else
+ if (SFILE(i, s) == NV_FILE_IMM) {
+ assert(!(pc->emit[1] & 0xc000));
+ assert(s == 1 || i->opcode == NV_OP_MOV);
+ set_immd(pc, i, s);
+ }
+ }
+}
+
+static void
+emit_form_1(struct nv_pc *pc, struct nv_instruction *i)
+{
+ int s;
+
+ set_pred(pc, i);
+
+ DID(pc, i->def[0], 14);
+
+ for (s = 0; s < 1 && i->src[s]; ++s) {
+ if (SFILE(i, s) >= NV_FILE_MEM_C(0) &&
+ SFILE(i, s) <= NV_FILE_MEM_C(15)) {
+ assert(!(pc->emit[1] & 0xc000));
+ assert(s <= 1);
+ pc->emit[1] |= 0x4000 | (const_space_index(i, s) << 10);
+ set_address_16(pc, i->src[s]);
+ } else
+ if (SFILE(i, s) == NV_FILE_GPR) {
+ SID(pc, i->src[s], 26);
+ } else
+ if (SFILE(i, s) == NV_FILE_IMM) {
+ assert(!(pc->emit[1] & 0xc000));
+ assert(s == 1 || i->opcode == NV_OP_MOV);
+ set_immd(pc, i, s);
+ }
+ }
+}
+
+static void
+emit_neg_abs_1_2(struct nv_pc *pc, struct nv_instruction *i)
+{
+ if (i->src[0]->mod & NV_MOD_ABS)
+ pc->emit[0] |= 1 << 7;
+ if (i->src[0]->mod & NV_MOD_NEG)
+ pc->emit[0] |= 1 << 9;
+ if (i->src[1]->mod & NV_MOD_ABS)
+ pc->emit[0] |= 1 << 6;
+ if (i->src[1]->mod & NV_MOD_NEG)
+ pc->emit[0] |= 1 << 8;
+}
+
+static void
+emit_add_f32(struct nv_pc *pc, struct nv_instruction *i)
+{
+ pc->emit[0] = 0x00000000;
+ pc->emit[1] = 0x50000000;
+
+ emit_form_0(pc, i);
+
+ emit_neg_abs_1_2(pc, i);
+
+ if (i->saturate)
+ pc->emit[1] |= 1 << 17;
+}
+
+static void
+emit_mul_f32(struct nv_pc *pc, struct nv_instruction *i)
+{
+ pc->emit[0] = 0x00000000;
+ pc->emit[1] = 0x58000000;
+
+ emit_form_0(pc, i);
+
+ if ((i->src[0]->mod ^ i->src[1]->mod) & NV_MOD_NEG)
+ pc->emit[1] |= 1 << 25;
+
+ if (i->saturate)
+ pc->emit[0] |= 1 << 5;
+}
+
+static void
+emit_mad_f32(struct nv_pc *pc, struct nv_instruction *i)
+{
+ pc->emit[0] = 0x00000000;
+ pc->emit[1] = 0x30000000;
+
+ emit_form_0(pc, i);
+
+ if ((i->src[0]->mod ^ i->src[1]->mod) & NV_MOD_NEG)
+ pc->emit[0] |= 1 << 9;
+
+ if (i->src[2]->mod & NV_MOD_NEG)
+ pc->emit[0] |= 1 << 8;
+
+ if (i->saturate)
+ pc->emit[0] |= 1 << 5;
+}
+
+static void
+emit_minmax(struct nv_pc *pc, struct nv_instruction *i)
+{
+ pc->emit[0] = 0x00000000;
+ pc->emit[1] = 0x08000000;
+
+ if (NV_BASEOP(i->opcode) == NV_OP_MAX)
+ pc->emit[1] |= 0x001e0000;
+ else
+ pc->emit[1] |= 0x000e0000; /* predicate ? */
+
+ emit_form_0(pc, i);
+
+ emit_neg_abs_1_2(pc, i);
+
+ switch (i->opcode) {
+ case NV_OP_MIN_U32:
+ case NV_OP_MAX_U32:
+ pc->emit[0] |= 3;
+ break;
+ case NV_OP_MIN_S32:
+ case NV_OP_MAX_S32:
+ pc->emit[0] |= 3 | (1 << 5);
+ break;
+ case NV_OP_MIN_F32:
+ case NV_OP_MAX_F32:
+ default:
+ break;
+ }
+}
+
+static void
+emit_tex(struct nv_pc *pc, struct nv_instruction *i)
+{
+ pc->emit[0] = 0x00000086;
+ pc->emit[1] = 0x80000000;
+
+ if (i->opcode == NV_OP_TXB) pc->emit[1] |= 0x04000000;
+ else
+ if (i->opcode == NV_OP_TXL) pc->emit[1] |= 0x06000000;
+
+ set_pred(pc, i);
+
+ if (1)
+ pc->emit[0] |= 63 << 26; /* explicit derivatives */
+
+ DID(pc, i->def[0], 14);
+ SID(pc, i->src[0], 20);
+
+ pc->emit[1] |= i->tex_mask << 14;
+ pc->emit[1] |= (i->tex_argc - 1) << 20;
+
+ assert(i->ext.tex.s < 16);
+
+ pc->emit[1] |= i->ext.tex.t;
+ pc->emit[1] |= i->ext.tex.s << 8;
+
+ if (i->tex_live)
+ pc->emit[0] |= 1 << 9;
+}
+
+/* 0: cos, 1: sin, 2: ex2, 3: lg2, 4: rcp, 5: rsqrt */
+static void
+emit_flop(struct nv_pc *pc, struct nv_instruction *i, ubyte op)
+{
+ pc->emit[0] = 0x00000000;
+ pc->emit[1] = 0xc8000000;
+
+ set_pred(pc, i);
+
+ DID(pc, i->def[0], 14);
+ SID(pc, i->src[0], 20);
+
+ pc->emit[0] |= op << 26;
+
+ if (op > 4) {
+ if (i->src[0]->mod & NV_MOD_NEG) pc->emit[0] |= 1 << 9;
+ if (i->src[0]->mod & NV_MOD_ABS) pc->emit[0] |= 1 << 7;
+ } else {
+ assert(!i->src[0]->mod);
+ }
+}
+
+static void
+emit_quadop(struct nv_pc *pc, struct nv_instruction *i)
+{
+ pc->emit[0] = 0x00000000;
+ pc->emit[1] = 0x48000000;
+
+ set_pred(pc, i);
+
+ assert(SFILE(i, 0) == NV_FILE_GPR && SFILE(i, 1) == NV_FILE_GPR);
+
+ DID(pc, i->def[0], 14);
+ SID(pc, i->src[0], 20);
+ SID(pc, i->src[0], 26);
+
+ pc->emit[0] |= i->lanes << 6; /* l0, l1, l2, l3, dx, dy */
+ pc->emit[1] |= i->quadop;
+}
+
+static void
+emit_ddx(struct nv_pc *pc, struct nv_instruction *i)
+{
+ i->quadop = 0x99;
+ i->lanes = 4;
+ emit_quadop(pc, i);
+}
+
+static void
+emit_ddy(struct nv_pc *pc, struct nv_instruction *i)
+{
+ i->quadop = 0xa5;
+ i->lanes = 5;
+ emit_quadop(pc, i);
+}
+
+/* preparation op (preex2, presin / convert to fixed point) */
+static void
+emit_preop(struct nv_pc *pc, struct nv_instruction *i)
+{
+ pc->emit[0] = 0x00000000;
+ pc->emit[1] = 0x60000000;
+
+ if (i->opcode == NV_OP_PREEX2)
+ pc->emit[0] |= 0x20;
+
+ emit_form_1(pc, i);
+
+ if (i->src[0]->mod & NV_MOD_NEG) pc->emit[0] |= 1 << 8;
+ if (i->src[0]->mod & NV_MOD_ABS) pc->emit[0] |= 1 << 6;
+}
+
+static void
+emit_shift(struct nv_pc *pc, struct nv_instruction *i)
+{
+ pc->emit[0] = 0x00000003;
+
+ switch (i->opcode) {
+ case NV_OP_SAR:
+ pc->emit[0] |= 0x20; /* fall through */
+ case NV_OP_SHR:
+ pc->emit[1] = 0x58000000;
+ break;
+ case NV_OP_SHL:
+ default:
+ pc->emit[1] = 0x60000000;
+ break;
+ }
+
+ emit_form_0(pc, i);
+}
+
+static void
+emit_bitop(struct nv_pc *pc, struct nv_instruction *i)
+{
+ if (SFILE(i, 1) == NV_FILE_IMM) {
+ pc->emit[0] = 0x00000002;
+ pc->emit[1] = 0x38000000;
+ } else {
+ pc->emit[0] = 0x00000003;
+ pc->emit[1] = 0x68000000;
+ }
+
+ switch (i->opcode) {
+ case NV_OP_OR:
+ pc->emit[0] |= 0x40;
+ break;
+ case NV_OP_XOR:
+ pc->emit[0] |= 0x80;
+ break;
+ case NV_OP_AND:
+ default:
+ break;
+ }
+
+ emit_form_0(pc, i);
+}
+
+static void
+emit_set(struct nv_pc *pc, struct nv_instruction *i)
+{
+ pc->emit[0] = 0x00000000;
+
+ switch (i->opcode) {
+ case NV_OP_SET_S32:
+ pc->emit[0] |= 0x20; /* fall through */
+ case NV_OP_SET_U32:
+ pc->emit[0] |= 0x3;
+ pc->emit[1] = 0x100e0000;
+ break;
+ case NV_OP_SET_F32_AND:
+ pc->emit[1] = 0x18000000;
+ break;
+ case NV_OP_SET_F32_OR:
+ pc->emit[1] = 0x18200000;
+ break;
+ case NV_OP_SET_F32_XOR:
+ pc->emit[1] = 0x18400000;
+ break;
+ case NV_OP_FSET_F32:
+ pc->emit[0] |= 0x20; /* fall through */
+ case NV_OP_SET_F32:
+ default:
+ pc->emit[1] = 0x180e0000;
+ break;
+ }
+
+ if (DFILE(i, 0) == NV_FILE_PRED) {
+ pc->emit[0] |= 0x1c000;
+ pc->emit[1] += 0x08000000;
+ }
+
+ pc->emit[1] |= i->set_cond << 23;
+
+ emit_form_0(pc, i);
+
+ emit_neg_abs_1_2(pc, i); /* maybe assert that U/S32 don't use mods */
+}
+
+static void
+emit_selp(struct nv_pc *pc, struct nv_instruction *i)
+{
+ pc->emit[0] = 0x00000004;
+ pc->emit[1] = 0x20000000;
+
+ emit_form_0(pc, i);
+
+ if (i->cc || (i->src[2]->mod & NV_MOD_NOT))
+ pc->emit[1] |= 1 << 20;
+}
+
+static void
+emit_slct(struct nv_pc *pc, struct nv_instruction *i)
+{
+ pc->emit[0] = 0x00000000;
+
+ switch (i->opcode) {
+ case NV_OP_SLCT_S32:
+ pc->emit[0] |= 0x20; /* fall through */
+ case NV_OP_SLCT_U32:
+ pc->emit[0] |= 0x3;
+ pc->emit[1] = 0x30000000;
+ break;
+ case NV_OP_SLCT_F32:
+ default:
+ pc->emit[1] = 0x38000000;
+ break;
+ }
+
+ emit_form_0(pc, i);
+
+ pc->emit[1] |= i->set_cond << 23;
+}
+
+static void
+emit_cvt(struct nv_pc *pc, struct nv_instruction *i)
+{
+ pc->emit[0] = 0x00000004;
+ pc->emit[1] = 0x10000000;
+
+ if (i->opcode != NV_OP_CVT)
+ i->ext.cvt.d = i->ext.cvt.s = NV_OPTYPE(i->opcode);
+
+ switch (i->ext.cvt.d) {
+ case NV_TYPE_F32:
+ switch (i->ext.cvt.s) {
+ case NV_TYPE_F32: pc->emit[1] = 0x10000000; break;
+ case NV_TYPE_S32: pc->emit[0] |= 0x200;
+ case NV_TYPE_U32: pc->emit[1] = 0x18000000; break;
+ }
+ break;
+ case NV_TYPE_S32: pc->emit[0] |= 0x80;
+ case NV_TYPE_U32:
+ switch (i->ext.cvt.s) {
+ case NV_TYPE_F32: pc->emit[1] = 0x14000000; break;
+ case NV_TYPE_S32: pc->emit[0] |= 0x200;
+ case NV_TYPE_U32: pc->emit[1] = 0x1c000000; break;
+ }
+ break;
+ default:
+ assert(!"cvt: unknown type");
+ break;
+ }
+
+ if (i->opcode == NV_OP_FLOOR)
+ pc->emit[1] |= 0x00020000;
+ else
+ if (i->opcode == NV_OP_CEIL)
+ pc->emit[1] |= 0x00040000;
+ else
+ if (i->opcode == NV_OP_TRUNC)
+ pc->emit[1] |= 0x00060000;
+
+ if (i->saturate || i->opcode == NV_OP_SAT)
+ pc->emit[0] |= 0x20;
+
+ if (NV_BASEOP(i->opcode) == NV_OP_ABS || i->src[0]->mod & NV_MOD_ABS)
+ pc->emit[0] |= 1 << 6;
+ if (NV_BASEOP(i->opcode) == NV_OP_NEG || i->src[0]->mod & NV_MOD_NEG)
+ pc->emit[0] |= 1 << 8;
+
+ pc->emit[0] |= util_logbase2(DREG(i->def[0])->size) << 20;
+ pc->emit[0] |= util_logbase2(SREG(i->src[0])->size) << 23;
+
+ emit_form_1(pc, i);
+}
+
+static void
+emit_interp(struct nv_pc *pc, struct nv_instruction *i)
+{
+ pc->emit[0] = 0x00000000;
+ pc->emit[1] = 0xc07e0000;
+
+ DID(pc, i->def[0], 14);
+
+ set_pred(pc, i);
+
+ if (i->indirect)
+ SID(pc, i->src[i->indirect], 20);
+ else
+ SID(pc, NULL, 20);
+
+ if (i->opcode == NV_OP_PINTERP) {
+ pc->emit[0] |= 0x040;
+ SID(pc, i->src[1], 26);
+ } else {
+ SID(pc, NULL, 26);
+ }
+
+ pc->emit[1] |= i->src[0]->value->reg.address & 0xffff;
+
+ if (i->centroid)
+ pc->emit[0] |= 0x100;
+ else
+ if (i->flat)
+ pc->emit[0] |= 0x080;
+}
+
+static void
+emit_vfetch(struct nv_pc *pc, struct nv_instruction *i)
+{
+ pc->emit[0] = 0x03f00006;
+ pc->emit[1] = 0x06000000 | i->src[0]->value->reg.address;
+ if (i->patch)
+ pc->emit[0] |= 0x100;
+
+ set_pred(pc, i);
+
+ DVS(pc, i);
+ DID(pc, i->def[0], 14);
+
+ SID(pc, (i->indirect >= 0) ? i->src[i->indirect] : NULL, 26);
+}
+
+static void
+emit_export(struct nv_pc *pc, struct nv_instruction *i)
+{
+ pc->emit[0] = 0x00000006;
+ pc->emit[1] = 0x0a000000;
+ if (i->patch)
+ pc->emit[0] |= 0x100;
+
+ set_pred(pc, i);
+
+ assert(SFILE(i, 0) == NV_FILE_MEM_V);
+ assert(SFILE(i, 1) == NV_FILE_GPR);
+
+ SID(pc, i->src[1], 26); /* register source */
+ SVS(pc, i->src[0]);
+
+ pc->emit[1] |= i->src[0]->value->reg.address & 0xfff;
+
+ SID(pc, (i->indirect >= 0) ? i->src[i->indirect] : NULL, 20);
+}
+
+static void
+emit_mov(struct nv_pc *pc, struct nv_instruction *i)
+{
+ if (i->opcode == NV_OP_MOV)
+ i->lanes = 0xf;
+
+ if (SFILE(i, 0) == NV_FILE_IMM) {
+ pc->emit[0] = 0x000001e2;
+ pc->emit[1] = 0x18000000;
+ } else
+ if (SFILE(i, 0) == NV_FILE_PRED) {
+ pc->emit[0] = 0x1c000004;
+ pc->emit[1] = 0x080e0000;
+ } else {
+ pc->emit[0] = 0x00000004 | (i->lanes << 5);
+ pc->emit[1] = 0x28000000;
+ }
+
+ emit_form_1(pc, i);
+}
+
+static void
+emit_ldst_size(struct nv_pc *pc, struct nv_instruction *i)
+{
+ assert(NV_IS_MEMORY_FILE(SFILE(i, 0)));
+
+ switch (SSIZE(i, 0)) {
+ case 1:
+ if (NV_TYPE_ISSGD(i->ext.cvt.s))
+ pc->emit[0] |= 0x20;
+ break;
+ case 2:
+ pc->emit[0] |= 0x40;
+ if (NV_TYPE_ISSGD(i->ext.cvt.s))
+ pc->emit[0] |= 0x20;
+ break;
+ case 4: pc->emit[0] |= 0x80; break;
+ case 8: pc->emit[0] |= 0xa0; break;
+ case 16: pc->emit[0] |= 0xc0; break;
+ default:
+ NOUVEAU_ERR("invalid load/store size %u\n", SSIZE(i, 0));
+ break;
+ }
+}
+
+static void
+emit_ld_const(struct nv_pc *pc, struct nv_instruction *i)
+{
+ pc->emit[0] = 0x00000006;
+ pc->emit[1] = 0x14000000 | (const_space_index(i, 0) << 10);
+
+ emit_ldst_size(pc, i);
+
+ set_pred(pc, i);
+ set_address_16(pc, i->src[0]);
+
+ SID(pc, (i->indirect >= 0) ? i->src[i->indirect] : NULL, 20);
+ DID(pc, i->def[0], 14);
+}
+
+static void
+emit_ld(struct nv_pc *pc, struct nv_instruction *i)
+{
+ if (SFILE(i, 0) >= NV_FILE_MEM_C(0) &&
+ SFILE(i, 0) <= NV_FILE_MEM_C(15)) {
+ emit_ld_const(pc, i);
+ } else {
+ NOUVEAU_ERR("emit_ld(%u): not handled yet\n", SFILE(i, 0));
+ abort();
+ }
+}
+
+static void
+emit_st(struct nv_pc *pc, struct nv_instruction *i)
+{
+ NOUVEAU_ERR("emit_st: not handled yet\n");
+ abort();
+}
+
+void
+nvc0_emit_instruction(struct nv_pc *pc, struct nv_instruction *i)
+{
+ debug_printf("EMIT: "); nvc0_print_instruction(i);
+
+ switch (i->opcode) {
+ case NV_OP_VFETCH:
+ emit_vfetch(pc, i);
+ break;
+ case NV_OP_EXPORT:
+ if (!pc->is_fragprog)
+ emit_export(pc, i);
+ break;
+ case NV_OP_MOV:
+ emit_mov(pc, i);
+ break;
+ case NV_OP_LD:
+ emit_ld(pc, i);
+ break;
+ case NV_OP_ST:
+ emit_st(pc, i);
+ break;
+ case NV_OP_LINTERP:
+ case NV_OP_PINTERP:
+ emit_interp(pc, i);
+ break;
+ case NV_OP_ADD_F32:
+ emit_add_f32(pc, i);
+ break;
+ case NV_OP_AND:
+ case NV_OP_OR:
+ case NV_OP_XOR:
+ emit_bitop(pc, i);
+ break;
+ case NV_OP_CVT:
+ case NV_OP_ABS_F32:
+ case NV_OP_ABS_S32:
+ case NV_OP_NEG_F32:
+ case NV_OP_NEG_S32:
+ case NV_OP_SAT:
+ case NV_OP_CEIL:
+ case NV_OP_FLOOR:
+ case NV_OP_TRUNC:
+ emit_cvt(pc, i);
+ break;
+ case NV_OP_DFDX:
+ emit_ddx(pc, i);
+ break;
+ case NV_OP_DFDY:
+ emit_ddy(pc, i);
+ break;
+ case NV_OP_COS:
+ emit_flop(pc, i, 0);
+ break;
+ case NV_OP_SIN:
+ emit_flop(pc, i, 1);
+ break;
+ case NV_OP_EX2:
+ emit_flop(pc, i, 2);
+ break;
+ case NV_OP_LG2:
+ emit_flop(pc, i, 3);
+ break;
+ case NV_OP_RCP:
+ emit_flop(pc, i, 4);
+ break;
+ case NV_OP_RSQ:
+ emit_flop(pc, i, 5);
+ break;
+ case NV_OP_PRESIN:
+ case NV_OP_PREEX2:
+ emit_preop(pc, i);
+ break;
+ case NV_OP_MAD_F32:
+ emit_mad_f32(pc, i);
+ break;
+ case NV_OP_MAX_F32:
+ case NV_OP_MAX_S32:
+ case NV_OP_MAX_U32:
+ case NV_OP_MIN_F32:
+ case NV_OP_MIN_S32:
+ case NV_OP_MIN_U32:
+ emit_minmax(pc, i);
+ break;
+ case NV_OP_MUL_F32:
+ emit_mul_f32(pc, i);
+ break;
+ case NV_OP_SET_F32:
+ case NV_OP_FSET_F32:
+ emit_set(pc, i);
+ break;
+ case NV_OP_SHL:
+ case NV_OP_SHR:
+ case NV_OP_SAR:
+ emit_shift(pc, i);
+ break;
+ case NV_OP_TEX:
+ case NV_OP_TXB:
+ case NV_OP_TXL:
+ emit_tex(pc, i);
+ break;
+ case NV_OP_BRA:
+ emit_flow(pc, i, 0x40);
+ break;
+ case NV_OP_CALL:
+ emit_flow(pc, i, 0x50);
+ break;
+ case NV_OP_JOINAT:
+ emit_flow(pc, i, 0x60);
+ break;
+ case NV_OP_EXIT:
+ emit_flow(pc, i, 0x80);
+ break;
+ case NV_OP_RET:
+ emit_flow(pc, i, 0x90);
+ break;
+ case NV_OP_KIL:
+ emit_flow(pc, i, 0x98);
+ break;
+ case NV_OP_JOIN:
+ case NV_OP_NOP:
+ pc->emit[0] = 0x00003c00;
+ pc->emit[1] = 0x00000000;
+ break;
+ case NV_OP_SELP:
+ emit_selp(pc, i);
+ break;
+ case NV_OP_SLCT_F32:
+ case NV_OP_SLCT_S32:
+ case NV_OP_SLCT_U32:
+ emit_slct(pc, i);
+ break;
+ default:
+ NOUVEAU_ERR("unhandled NV_OP: %d\n", i->opcode);
+ abort();
+ break;
+ }
+
+ if (i->join)
+ pc->emit[0] |= 0x10;
+}