Merge branch 'vbo-0.2'
[mesa.git] / src / mesa / drivers / dri / nouveau / nv40_vertprog.c
1 #include "nouveau_shader.h"
2 #include "nouveau_msg.h"
3 #include "nv40_shader.h"
4
5 /*****************************************************************************
6 * Assembly routines
7 */
8 static int
9 NV40VPSupportsOpcode(nvsFunc * shader, nvsOpcode op)
10 {
11 if (shader->GetOPTXFromSOP(op, NULL))
12 return 1;
13 return 0;
14 }
15
16 static void
17 NV40VPSetOpcode(nvsFunc *shader, unsigned int opcode, int slot)
18 {
19 if (slot) {
20 shader->inst[1] &= ~NV40_VP_INST_SCA_OPCODE_MASK;
21 shader->inst[1] |= (opcode << NV40_VP_INST_SCA_OPCODE_SHIFT);
22 } else {
23 shader->inst[1] &= ~NV40_VP_INST_VEC_OPCODE_MASK;
24 shader->inst[1] |= (opcode << NV40_VP_INST_VEC_OPCODE_SHIFT);
25 }
26 }
27
28 static void
29 NV40VPSetCCUpdate(nvsFunc *shader)
30 {
31 shader->inst[0] |= NV40_VP_INST_COND_UPDATE_ENABLE;
32 }
33
34 static void
35 NV40VPSetCondition(nvsFunc *shader, int on, nvsCond cond, int reg,
36 nvsSwzComp *swizzle)
37 {
38 unsigned int hwcond;
39
40 if (on ) shader->inst[0] |= NV40_VP_INST_COND_TEST_ENABLE;
41 else shader->inst[0] &= ~NV40_VP_INST_COND_TEST_ENABLE;
42 if (reg) shader->inst[0] |= NV40_VP_INST_COND_REG_SELECT_1;
43 else shader->inst[0] &= ~NV40_VP_INST_COND_REG_SELECT_1;
44
45 switch (cond) {
46 case NVS_COND_TR: hwcond = NV40_VP_INST_COND_TR; break;
47 case NVS_COND_FL: hwcond = NV40_VP_INST_COND_FL; break;
48 case NVS_COND_LT: hwcond = NV40_VP_INST_COND_LT; break;
49 case NVS_COND_GT: hwcond = NV40_VP_INST_COND_GT; break;
50 case NVS_COND_NE: hwcond = NV40_VP_INST_COND_NE; break;
51 case NVS_COND_EQ: hwcond = NV40_VP_INST_COND_EQ; break;
52 case NVS_COND_GE: hwcond = NV40_VP_INST_COND_GE; break;
53 case NVS_COND_LE: hwcond = NV40_VP_INST_COND_LE; break;
54 default:
55 WARN_ONCE("unknown vp cond %d\n", cond);
56 hwcond = NV40_VP_INST_COND_TR;
57 break;
58 }
59 shader->inst[0] &= ~NV40_VP_INST_COND_MASK;
60 shader->inst[0] |= (hwcond << NV40_VP_INST_COND_SHIFT);
61
62 shader->inst[0] &= ~NV40_VP_INST_COND_SWZ_ALL_MASK;
63 shader->inst[0] |= (swizzle[NVS_SWZ_X] << NV40_VP_INST_COND_SWZ_X_SHIFT);
64 shader->inst[0] |= (swizzle[NVS_SWZ_Y] << NV40_VP_INST_COND_SWZ_Y_SHIFT);
65 shader->inst[0] |= (swizzle[NVS_SWZ_Z] << NV40_VP_INST_COND_SWZ_Z_SHIFT);
66 shader->inst[0] |= (swizzle[NVS_SWZ_W] << NV40_VP_INST_COND_SWZ_W_SHIFT);
67 }
68
69 /* these just exist here until nouveau_reg.h has them. */
70 #define NV30_TCL_PRIMITIVE_3D_VP_OUT_REG_COL0 (1<<0)
71 #define NV30_TCL_PRIMITIVE_3D_VP_OUT_REG_COL1 (1<<1)
72 #define NV30_TCL_PRIMITIVE_3D_VP_OUT_REG_BFC0 (1<<2)
73 #define NV30_TCL_PRIMITIVE_3D_VP_OUT_REG_BFC1 (1<<3)
74 #define NV30_TCL_PRIMITIVE_3D_VP_OUT_REG_FOGC (1<<4)
75 #define NV30_TCL_PRIMITIVE_3D_VP_OUT_REG_PSZ (1<<5)
76 #define NV30_TCL_PRIMITIVE_3D_VP_OUT_REG_CLP0 (1<<6)
77 #define NV30_TCL_PRIMITIVE_3D_VP_OUT_REG_CLP1 (1<<7)
78 #define NV30_TCL_PRIMITIVE_3D_VP_OUT_REG_CLP2 (1<<8)
79 #define NV30_TCL_PRIMITIVE_3D_VP_OUT_REG_CLP3 (1<<9)
80 #define NV30_TCL_PRIMITIVE_3D_VP_OUT_REG_CLP4 (1<<10)
81 #define NV30_TCL_PRIMITIVE_3D_VP_OUT_REG_CLP5 (1<<11)
82 #define NV30_TCL_PRIMITIVE_3D_VP_OUT_REG_TEX0 (1<<14)
83
84 static unsigned int
85 NV40VPTranslateResultReg(nvsFunc *shader, nvsFixedReg result,
86 unsigned int *mask_ret)
87 {
88 unsigned int *out_reg = &shader->card_priv->NV30VP.vp_out_reg;
89 unsigned int *clip_en = &shader->card_priv->NV30VP.clip_enables;
90
91 *mask_ret = 0xf;
92
93 switch (result) {
94 case NVS_FR_POSITION:
95 /* out_reg POS implied */
96 return NV40_VP_INST_DEST_POS;
97 case NVS_FR_COL0:
98 (*out_reg) |= NV30_TCL_PRIMITIVE_3D_VP_OUT_REG_COL0;
99 return NV40_VP_INST_DEST_COL0;
100 case NVS_FR_COL1:
101 (*out_reg) |= NV30_TCL_PRIMITIVE_3D_VP_OUT_REG_COL1;
102 return NV40_VP_INST_DEST_COL1;
103 case NVS_FR_BFC0:
104 (*out_reg) |= NV30_TCL_PRIMITIVE_3D_VP_OUT_REG_BFC0;
105 return NV40_VP_INST_DEST_BFC0;
106 case NVS_FR_BFC1:
107 (*out_reg) |= NV30_TCL_PRIMITIVE_3D_VP_OUT_REG_BFC1;
108 return NV40_VP_INST_DEST_BFC1;
109 case NVS_FR_FOGCOORD:
110 (*out_reg) |= NV30_TCL_PRIMITIVE_3D_VP_OUT_REG_FOGC;
111 *mask_ret = 0x8;
112 return NV40_VP_INST_DEST_FOGC;
113 case NVS_FR_CLIP0:
114 (*out_reg) |= NV30_TCL_PRIMITIVE_3D_VP_OUT_REG_CLP0;
115 (*clip_en) |= 0x00000002;
116 *mask_ret = 0x4;
117 return NV40_VP_INST_DEST_FOGC;
118 case NVS_FR_CLIP1:
119 (*out_reg) |= NV30_TCL_PRIMITIVE_3D_VP_OUT_REG_CLP1;
120 (*clip_en) |= 0x00000020;
121 *mask_ret = 0x2;
122 return NV40_VP_INST_DEST_FOGC;
123 case NVS_FR_CLIP2:
124 (*out_reg) |= NV30_TCL_PRIMITIVE_3D_VP_OUT_REG_CLP2;
125 (*clip_en) |= 0x00000200;
126 *mask_ret = 0x1;
127 return NV40_VP_INST_DEST_FOGC;
128 case NVS_FR_POINTSZ:
129 (*out_reg) |= NV30_TCL_PRIMITIVE_3D_VP_OUT_REG_PSZ;
130 *mask_ret = 0x8;
131 return NV40_VP_INST_DEST_PSZ;
132 case NVS_FR_CLIP3:
133 (*out_reg) |= NV30_TCL_PRIMITIVE_3D_VP_OUT_REG_CLP3;
134 (*clip_en) |= 0x00002000;
135 *mask_ret = 0x4;
136 return NV40_VP_INST_DEST_PSZ;
137 case NVS_FR_CLIP4:
138 (*clip_en) |= 0x00020000;
139 (*out_reg) |= NV30_TCL_PRIMITIVE_3D_VP_OUT_REG_CLP4;
140 *mask_ret = 0x2;
141 return NV40_VP_INST_DEST_PSZ;
142 case NVS_FR_CLIP5:
143 (*clip_en) |= 0x00200000;
144 (*out_reg) |= NV30_TCL_PRIMITIVE_3D_VP_OUT_REG_CLP5;
145 *mask_ret = 0x1;
146 return NV40_VP_INST_DEST_PSZ;
147 case NVS_FR_TEXCOORD0:
148 case NVS_FR_TEXCOORD1:
149 case NVS_FR_TEXCOORD2:
150 case NVS_FR_TEXCOORD3:
151 case NVS_FR_TEXCOORD4:
152 case NVS_FR_TEXCOORD5:
153 case NVS_FR_TEXCOORD6:
154 case NVS_FR_TEXCOORD7:
155 {
156 int unit = result - NVS_FR_TEXCOORD0;
157 (*out_reg) |= (NV30_TCL_PRIMITIVE_3D_VP_OUT_REG_TEX0 << unit);
158 return NV40_VP_INST_DEST_TC(unit);
159 }
160 default:
161 WARN_ONCE("unknown vp output %d\n", result);
162 return NV40_VP_INST_DEST_POS;
163 }
164 }
165
166 static void
167 NV40VPSetResult(nvsFunc *shader, nvsRegister * dest, unsigned int mask,
168 int slot)
169 {
170 unsigned int hwmask = 0;
171
172 if (mask & SMASK_X) hwmask |= (1 << 3);
173 if (mask & SMASK_Y) hwmask |= (1 << 2);
174 if (mask & SMASK_Z) hwmask |= (1 << 1);
175 if (mask & SMASK_W) hwmask |= (1 << 0);
176
177 if (dest->file == NVS_FILE_RESULT) {
178 unsigned int valid_mask;
179 int hwidx;
180
181 hwidx = NV40VPTranslateResultReg(shader, dest->index, &valid_mask);
182 if (hwmask & ~valid_mask)
183 WARN_ONCE("writing invalid components of result reg\n");
184 hwmask &= valid_mask;
185
186 shader->inst[3] &= ~NV40_VP_INST_DEST_MASK;
187 shader->inst[3] |= (hwidx << NV40_VP_INST_DEST_SHIFT);
188
189 if (slot) shader->inst[3] |= NV40_VP_INST_SCA_RESULT;
190 else shader->inst[0] |= NV40_VP_INST_VEC_RESULT;
191 } else {
192 /* NVS_FILE_TEMP || NVS_FILE_ADDRESS */
193 if (slot) {
194 shader->inst[3] &= ~NV40_VP_INST_SCA_RESULT;
195 shader->inst[3] &= ~NV40_VP_INST_SCA_DEST_TEMP_MASK;
196 shader->inst[3] |= (dest->index << NV40_VP_INST_SCA_DEST_TEMP_SHIFT);
197 } else {
198 shader->inst[0] &= ~NV40_VP_INST_VEC_RESULT;
199 shader->inst[0] &= ~(NV40_VP_INST_VEC_DEST_TEMP_MASK | (1<<20));
200 shader->inst[0] |= (dest->index << NV40_VP_INST_VEC_DEST_TEMP_SHIFT);
201 }
202 }
203
204 if (slot) {
205 shader->inst[3] &= ~NV40_VP_INST_SCA_WRITEMASK_MASK;
206 shader->inst[3] |= (hwmask << NV40_VP_INST_SCA_WRITEMASK_SHIFT);
207 } else {
208 shader->inst[3] &= ~NV40_VP_INST_VEC_WRITEMASK_MASK;
209 shader->inst[3] |= (hwmask << NV40_VP_INST_VEC_WRITEMASK_SHIFT);
210 }
211 }
212
213 static void
214 NV40VPInsertSource(nvsFunc *shader, unsigned int hw, int pos)
215 {
216 switch (pos) {
217 case 0:
218 shader->inst[1] &= ~NV40_VP_INST_SRC0H_MASK;
219 shader->inst[2] &= ~NV40_VP_INST_SRC0L_MASK;
220 shader->inst[1] |= ((hw & NV40_VP_SRC0_HIGH_MASK) >>
221 NV40_VP_SRC0_HIGH_SHIFT)
222 << NV40_VP_INST_SRC0H_SHIFT;
223 shader->inst[2] |= (hw & NV40_VP_SRC0_LOW_MASK)
224 << NV40_VP_INST_SRC0L_SHIFT;
225 break;
226 case 1:
227 shader->inst[2] &= ~NV40_VP_INST_SRC1_MASK;
228 shader->inst[2] |= hw
229 << NV40_VP_INST_SRC1_SHIFT;
230 break;
231 case 2:
232 shader->inst[2] &= ~NV40_VP_INST_SRC2H_MASK;
233 shader->inst[3] &= ~NV40_VP_INST_SRC2L_MASK;
234 shader->inst[2] |= ((hw & NV40_VP_SRC2_HIGH_MASK) >>
235 NV40_VP_SRC2_HIGH_SHIFT)
236 << NV40_VP_INST_SRC2H_SHIFT;
237 shader->inst[3] |= (hw & NV40_VP_SRC2_LOW_MASK)
238 << NV40_VP_INST_SRC2L_SHIFT;
239 break;
240 default:
241 assert(0);
242 break;
243 }
244 }
245
246 static void
247 NV40VPSetSource(nvsFunc *shader, nvsRegister * src, int pos)
248 {
249 unsigned int hw = 0;
250
251 switch (src->file) {
252 case NVS_FILE_ADDRESS:
253 break;
254 case NVS_FILE_ATTRIB:
255 hw |= (NV40_VP_SRC_REG_TYPE_INPUT << NV40_VP_SRC_REG_TYPE_SHIFT);
256
257 shader->inst[1] &= ~NV40_VP_INST_INPUT_SRC_MASK;
258 shader->inst[1] |= (src->index << NV40_VP_INST_INPUT_SRC_SHIFT);
259 shader->card_priv->NV30VP.vp_in_reg |= (1 << src->index);
260 if (src->indexed) {
261 shader->inst[0] |= NV40_VP_INST_INDEX_INPUT;
262 if (src->addr_reg)
263 shader->inst[0] |= NV40_VP_INST_ADDR_REG_SELECT_1;
264 else
265 shader->inst[0] &= ~NV40_VP_INST_ADDR_REG_SELECT_1;
266 shader->inst[0] &= ~NV40_VP_INST_ADDR_SWZ_SHIFT;
267 shader->inst[0] |= (src->addr_comp << NV40_VP_INST_ADDR_SWZ_SHIFT);
268 } else
269 shader->inst[0] &= ~NV40_VP_INST_INDEX_INPUT;
270 break;
271 case NVS_FILE_CONST:
272 hw |= (NV40_VP_SRC_REG_TYPE_CONST << NV40_VP_SRC_REG_TYPE_SHIFT);
273
274 shader->inst[1] &= ~NV40_VP_INST_CONST_SRC_MASK;
275 shader->inst[1] |= (src->index << NV40_VP_INST_CONST_SRC_SHIFT);
276 if (src->indexed) {
277 shader->inst[3] |= NV40_VP_INST_INDEX_CONST;
278 if (src->addr_reg)
279 shader->inst[0] |= NV40_VP_INST_ADDR_REG_SELECT_1;
280 else
281 shader->inst[0] &= ~NV40_VP_INST_ADDR_REG_SELECT_1;
282 shader->inst[0] &= ~NV40_VP_INST_ADDR_SWZ_MASK;
283 shader->inst[0] |= (src->addr_comp << NV40_VP_INST_ADDR_SWZ_SHIFT);
284 } else
285 shader->inst[3] &= ~NV40_VP_INST_INDEX_CONST;
286 break;
287 case NVS_FILE_TEMP:
288 hw |= (NV40_VP_SRC_REG_TYPE_TEMP << NV40_VP_SRC_REG_TYPE_SHIFT);
289 hw |= (src->index << NV40_VP_SRC_TEMP_SRC_SHIFT);
290 break;
291 default:
292 fprintf(stderr, "unknown source file %d\n", src->file);
293 assert(0);
294 break;
295 }
296
297 if (src->file != NVS_FILE_ADDRESS) {
298 if (src->negate)
299 hw |= NV40_VP_SRC_NEGATE;
300 if (src->abs)
301 shader->inst[0] |= (1 << (21 + pos));
302 else
303 shader->inst[0] &= ~(1 << (21 + pos));
304 hw |= (src->swizzle[0] << NV40_VP_SRC_SWZ_X_SHIFT);
305 hw |= (src->swizzle[1] << NV40_VP_SRC_SWZ_Y_SHIFT);
306 hw |= (src->swizzle[2] << NV40_VP_SRC_SWZ_Z_SHIFT);
307 hw |= (src->swizzle[3] << NV40_VP_SRC_SWZ_W_SHIFT);
308
309 NV40VPInsertSource(shader, hw, pos);
310 }
311 }
312
313 static void
314 NV40VPSetBranchTarget(nvsFunc *shader, int addr)
315 {
316 shader->inst[2] &= ~NV40_VP_INST_IADDRH_MASK;
317 shader->inst[2] |= ((addr & 0xf8) >> 3) << NV40_VP_INST_IADDRH_SHIFT;
318 shader->inst[3] &= ~NV40_VP_INST_IADDRL_MASK;
319 shader->inst[3] |= ((addr & 0x07) << NV40_VP_INST_IADDRL_SHIFT);
320 }
321
322 static void
323 NV40VPInitInstruction(nvsFunc *shader)
324 {
325 unsigned int hwsrc = 0;
326
327 shader->inst[0] = /*NV40_VP_INST_VEC_RESULT | */
328 NV40_VP_INST_VEC_DEST_TEMP_MASK | (1<<20);
329 shader->inst[1] = 0;
330 shader->inst[2] = 0;
331 shader->inst[3] = NV40_VP_INST_SCA_RESULT |
332 NV40_VP_INST_SCA_DEST_TEMP_MASK |
333 NV40_VP_INST_DEST_MASK;
334
335 hwsrc = (NV40_VP_SRC_REG_TYPE_INPUT << NV40_VP_SRC_REG_TYPE_SHIFT) |
336 (NVS_SWZ_X << NV40_VP_SRC_SWZ_X_SHIFT) |
337 (NVS_SWZ_Y << NV40_VP_SRC_SWZ_Y_SHIFT) |
338 (NVS_SWZ_Z << NV40_VP_SRC_SWZ_Z_SHIFT) |
339 (NVS_SWZ_W << NV40_VP_SRC_SWZ_W_SHIFT);
340 NV40VPInsertSource(shader, hwsrc, 0);
341 NV40VPInsertSource(shader, hwsrc, 1);
342 NV40VPInsertSource(shader, hwsrc, 2);
343 }
344
345 static void
346 NV40VPSetLastInst(nvsFunc *shader)
347 {
348 shader->inst[3] |= 1;
349 }
350
351 /*****************************************************************************
352 * Disassembly routines
353 */
354 static int
355 NV40VPHasMergedInst(nvsFunc * shader)
356 {
357 if (shader->GetOpcodeHW(shader, 0) != NV40_VP_INST_OP_NOP &&
358 shader->GetOpcodeHW(shader, 1) != NV40_VP_INST_OP_NOP)
359 return 1;
360 return 0;
361 }
362
363 static unsigned int
364 NV40VPGetOpcodeHW(nvsFunc * shader, int slot)
365 {
366 int op;
367
368 if (slot)
369 op = (shader->inst[1] & NV40_VP_INST_SCA_OPCODE_MASK)
370 >> NV40_VP_INST_SCA_OPCODE_SHIFT;
371 else
372 op = (shader->inst[1] & NV40_VP_INST_VEC_OPCODE_MASK)
373 >> NV40_VP_INST_VEC_OPCODE_SHIFT;
374
375 return op;
376 }
377
378 static nvsRegFile
379 NV40VPGetDestFile(nvsFunc * shader, int merged)
380 {
381 nvsOpcode op;
382
383 op = shader->GetOpcode(shader, merged);
384 switch (op) {
385 case NVS_OP_ARL:
386 case NVS_OP_ARR:
387 case NVS_OP_ARA:
388 case NVS_OP_POPA:
389 return NVS_FILE_ADDRESS;
390 default:
391 if (shader->GetOpcodeSlot(shader, merged)) {
392 if (shader->inst[3] & NV40_VP_INST_SCA_RESULT)
393 return NVS_FILE_RESULT;
394 }
395 else {
396 if (shader->inst[0] & NV40_VP_INST_VEC_RESULT)
397 return NVS_FILE_RESULT;
398 }
399 return NVS_FILE_TEMP;
400 }
401
402 }
403
404 static unsigned int
405 NV40VPGetDestID(nvsFunc * shader, int merged)
406 {
407 int id;
408
409 switch (shader->GetDestFile(shader, merged)) {
410 case NVS_FILE_RESULT:
411 id = ((shader->inst[3] & NV40_VP_INST_DEST_MASK)
412 >> NV40_VP_INST_DEST_SHIFT);
413 switch (id) {
414 case NV40_VP_INST_DEST_POS : return NVS_FR_POSITION;
415 case NV40_VP_INST_DEST_COL0: return NVS_FR_COL0;
416 case NV40_VP_INST_DEST_COL1: return NVS_FR_COL1;
417 case NV40_VP_INST_DEST_BFC0: return NVS_FR_BFC0;
418 case NV40_VP_INST_DEST_BFC1: return NVS_FR_BFC1;
419 case NV40_VP_INST_DEST_FOGC: {
420 int mask = shader->GetDestMask(shader, merged);
421 switch (mask) {
422 case SMASK_X: return NVS_FR_FOGCOORD;
423 case SMASK_Y: return NVS_FR_CLIP0;
424 case SMASK_Z: return NVS_FR_CLIP1;
425 case SMASK_W: return NVS_FR_CLIP2;
426 default:
427 printf("more than 1 mask component set in FOGC writemask!\n");
428 return NVS_FR_UNKNOWN;
429 }
430 }
431 case NV40_VP_INST_DEST_PSZ:
432 {
433 int mask = shader->GetDestMask(shader, merged);
434 switch (mask) {
435 case SMASK_X: return NVS_FR_POINTSZ;
436 case SMASK_Y: return NVS_FR_CLIP3;
437 case SMASK_Z: return NVS_FR_CLIP4;
438 case SMASK_W: return NVS_FR_CLIP5;
439 default:
440 printf("more than 1 mask component set in PSZ writemask!\n");
441 return NVS_FR_UNKNOWN;
442 }
443 }
444 case NV40_VP_INST_DEST_TC(0): return NVS_FR_TEXCOORD0;
445 case NV40_VP_INST_DEST_TC(1): return NVS_FR_TEXCOORD1;
446 case NV40_VP_INST_DEST_TC(2): return NVS_FR_TEXCOORD2;
447 case NV40_VP_INST_DEST_TC(3): return NVS_FR_TEXCOORD3;
448 case NV40_VP_INST_DEST_TC(4): return NVS_FR_TEXCOORD4;
449 case NV40_VP_INST_DEST_TC(5): return NVS_FR_TEXCOORD5;
450 case NV40_VP_INST_DEST_TC(6): return NVS_FR_TEXCOORD6;
451 case NV40_VP_INST_DEST_TC(7): return NVS_FR_TEXCOORD7;
452 default:
453 return -1;
454 }
455 case NVS_FILE_ADDRESS:
456 /* Instructions that write address regs are encoded as if
457 * they would write temps.
458 */
459 case NVS_FILE_TEMP:
460 if (shader->GetOpcodeSlot(shader, merged))
461 id = ((shader->inst[3] & NV40_VP_INST_SCA_DEST_TEMP_MASK)
462 >> NV40_VP_INST_SCA_DEST_TEMP_SHIFT);
463 else
464 id = ((shader->inst[0] & NV40_VP_INST_VEC_DEST_TEMP_MASK)
465 >> NV40_VP_INST_VEC_DEST_TEMP_SHIFT);
466 return id;
467 default:
468 return -1;
469 }
470 }
471
472 static unsigned int
473 NV40VPGetDestMask(nvsFunc * shader, int merged)
474 {
475 unsigned int mask = 0;
476
477 if (shader->GetOpcodeSlot(shader, merged)) {
478 if (shader->inst[3] & NV40_VP_INST_SCA_WRITEMASK_X) mask |= SMASK_X;
479 if (shader->inst[3] & NV40_VP_INST_SCA_WRITEMASK_Y) mask |= SMASK_Y;
480 if (shader->inst[3] & NV40_VP_INST_SCA_WRITEMASK_Z) mask |= SMASK_Z;
481 if (shader->inst[3] & NV40_VP_INST_SCA_WRITEMASK_W) mask |= SMASK_W;
482 } else {
483 if (shader->inst[3] & NV40_VP_INST_VEC_WRITEMASK_X) mask |= SMASK_X;
484 if (shader->inst[3] & NV40_VP_INST_VEC_WRITEMASK_Y) mask |= SMASK_Y;
485 if (shader->inst[3] & NV40_VP_INST_VEC_WRITEMASK_Z) mask |= SMASK_Z;
486 if (shader->inst[3] & NV40_VP_INST_VEC_WRITEMASK_W) mask |= SMASK_W;
487 }
488
489 return mask;
490 }
491
492 static unsigned int
493 NV40VPGetSourceHW(nvsFunc * shader, int merged, int pos)
494 {
495 struct _op_xlat *opr;
496 unsigned int src;
497
498 opr = shader->GetOPTXRec(shader, merged);
499 if (!opr)
500 return -1;
501
502 switch (opr->srcpos[pos]) {
503 case 0:
504 src = ((shader->inst[1] & NV40_VP_INST_SRC0H_MASK)
505 >> NV40_VP_INST_SRC0H_SHIFT)
506 << NV40_VP_SRC0_HIGH_SHIFT;
507 src |= ((shader->inst[2] & NV40_VP_INST_SRC0L_MASK)
508 >> NV40_VP_INST_SRC0L_SHIFT);
509 break;
510 case 1:
511 src = ((shader->inst[2] & NV40_VP_INST_SRC1_MASK)
512 >> NV40_VP_INST_SRC1_SHIFT);
513 break;
514 case 2:
515 src = ((shader->inst[2] & NV40_VP_INST_SRC2H_MASK)
516 >> NV40_VP_INST_SRC2H_SHIFT)
517 << NV40_VP_SRC2_HIGH_SHIFT;
518 src |= ((shader->inst[3] & NV40_VP_INST_SRC2L_MASK)
519 >> NV40_VP_INST_SRC2L_SHIFT);
520 break;
521 default:
522 src = -1;
523 }
524
525 return src;
526 }
527
528 static nvsRegFile
529 NV40VPGetSourceFile(nvsFunc * shader, int merged, int pos)
530 {
531 unsigned int src;
532 struct _op_xlat *opr;
533 int file;
534
535 opr = shader->GetOPTXRec(shader, merged);
536 if (!opr || opr->srcpos[pos] == -1)
537 return -1;
538
539 switch (opr->srcpos[pos]) {
540 case SPOS_ADDRESS: return NVS_FILE_ADDRESS;
541 default:
542 src = shader->GetSourceHW(shader, merged, pos);
543 file = (src & NV40_VP_SRC_REG_TYPE_MASK) >> NV40_VP_SRC_REG_TYPE_SHIFT;
544
545 switch (file) {
546 case NV40_VP_SRC_REG_TYPE_TEMP : return NVS_FILE_TEMP;
547 case NV40_VP_SRC_REG_TYPE_INPUT: return NVS_FILE_ATTRIB;
548 case NV40_VP_SRC_REG_TYPE_CONST: return NVS_FILE_CONST;
549 default:
550 return NVS_FILE_UNKNOWN;
551 }
552 }
553 }
554
555 static int
556 NV40VPGetSourceID(nvsFunc * shader, int merged, int pos)
557 {
558 switch (shader->GetSourceFile(shader, merged, pos)) {
559 case NVS_FILE_ATTRIB:
560 switch ((shader->inst[1] & NV40_VP_INST_INPUT_SRC_MASK)
561 >> NV40_VP_INST_INPUT_SRC_SHIFT) {
562 case NV40_VP_INST_IN_POS: return NVS_FR_POSITION;
563 case NV40_VP_INST_IN_WEIGHT: return NVS_FR_WEIGHT;
564 case NV40_VP_INST_IN_NORMAL: return NVS_FR_NORMAL;
565 case NV40_VP_INST_IN_COL0: return NVS_FR_COL0;
566 case NV40_VP_INST_IN_COL1: return NVS_FR_COL1;
567 case NV40_VP_INST_IN_FOGC: return NVS_FR_FOGCOORD;
568 case NV40_VP_INST_IN_TC(0): return NVS_FR_TEXCOORD0;
569 case NV40_VP_INST_IN_TC(1): return NVS_FR_TEXCOORD1;
570 case NV40_VP_INST_IN_TC(2): return NVS_FR_TEXCOORD2;
571 case NV40_VP_INST_IN_TC(3): return NVS_FR_TEXCOORD3;
572 case NV40_VP_INST_IN_TC(4): return NVS_FR_TEXCOORD4;
573 case NV40_VP_INST_IN_TC(5): return NVS_FR_TEXCOORD5;
574 case NV40_VP_INST_IN_TC(6): return NVS_FR_TEXCOORD6;
575 case NV40_VP_INST_IN_TC(7): return NVS_FR_TEXCOORD7;
576 default:
577 return -1;
578 }
579 break;
580 case NVS_FILE_CONST:
581 return ((shader->inst[1] & NV40_VP_INST_CONST_SRC_MASK)
582 >> NV40_VP_INST_CONST_SRC_SHIFT);
583 case NVS_FILE_TEMP:
584 {
585 unsigned int src;
586
587 src = shader->GetSourceHW(shader, merged, pos);
588 return ((src & NV40_VP_SRC_TEMP_SRC_MASK) >>
589 NV40_VP_SRC_TEMP_SRC_SHIFT);
590 }
591 default:
592 return -1;
593 }
594 }
595
596 static int
597 NV40VPGetSourceNegate(nvsFunc * shader, int merged, int pos)
598 {
599 unsigned int src;
600
601 src = shader->GetSourceHW(shader, merged, pos);
602
603 if (src == -1)
604 return -1;
605 return ((src & NV40_VP_SRC_NEGATE) ? 1 : 0);
606 }
607
608 static void
609 NV40VPGetSourceSwizzle(nvsFunc * shader, int merged, int pos, nvsSwzComp *swz)
610 {
611 unsigned int src;
612 int swzbits;
613
614 src = shader->GetSourceHW(shader, merged, pos);
615 swzbits = (src & NV40_VP_SRC_SWZ_ALL_MASK) >> NV40_VP_SRC_SWZ_ALL_SHIFT;
616 NV20VPTXSwizzle(swzbits, swz);
617 }
618
619 static int
620 NV40VPGetSourceIndexed(nvsFunc * shader, int merged, int pos)
621 {
622 switch (shader->GetSourceFile(shader, merged, pos)) {
623 case NVS_FILE_ATTRIB:
624 return ((shader->inst[0] & NV40_VP_INST_INDEX_INPUT) ? 1 : 0);
625 case NVS_FILE_CONST:
626 return ((shader->inst[3] & NV40_VP_INST_INDEX_CONST) ? 1 : 0);
627 default:
628 return 0;
629 }
630 }
631
632 static nvsSwzComp
633 NV40VPGetAddressRegSwizzle(nvsFunc * shader)
634 {
635 nvsSwzComp swz;
636
637 swz = NV20VP_TX_SWIZZLE[(shader->inst[0] & NV40_VP_INST_ADDR_SWZ_MASK)
638 >> NV40_VP_INST_ADDR_SWZ_SHIFT];
639 return swz;
640 }
641
642 static int
643 NV40VPSupportsConditional(nvsFunc * shader)
644 {
645 /*FIXME: Is this true of all ops? */
646 return 1;
647 }
648
649 static int
650 NV40VPGetConditionUpdate(nvsFunc * shader)
651 {
652 return ((shader->inst[0] & NV40_VP_INST_COND_UPDATE_ENABLE) ? 1 : 0);
653 }
654
655 static int
656 NV40VPGetConditionTest(nvsFunc * shader)
657 {
658 int op;
659
660 /* The condition test is unconditionally enabled on some
661 * instructions. ie: the condition test bit does *NOT* have
662 * to be set.
663 *
664 * FIXME: check other relevant ops for this situation.
665 */
666 op = shader->GetOpcodeHW(shader, 1);
667 switch (op) {
668 case NV40_VP_INST_OP_BRA:
669 return 1;
670 default:
671 return ((shader->inst[0] & NV40_VP_INST_COND_TEST_ENABLE) ? 1 : 0);
672 }
673 }
674
675 static nvsCond
676 NV40VPGetCondition(nvsFunc * shader)
677 {
678 int cond;
679
680 cond = ((shader->inst[0] & NV40_VP_INST_COND_MASK)
681 >> NV40_VP_INST_COND_SHIFT);
682
683 switch (cond) {
684 case NV40_VP_INST_COND_FL: return NVS_COND_FL;
685 case NV40_VP_INST_COND_LT: return NVS_COND_LT;
686 case NV40_VP_INST_COND_EQ: return NVS_COND_EQ;
687 case NV40_VP_INST_COND_LE: return NVS_COND_LE;
688 case NV40_VP_INST_COND_GT: return NVS_COND_GT;
689 case NV40_VP_INST_COND_NE: return NVS_COND_NE;
690 case NV40_VP_INST_COND_GE: return NVS_COND_GE;
691 case NV40_VP_INST_COND_TR: return NVS_COND_TR;
692 default:
693 return NVS_COND_UNKNOWN;
694 }
695 }
696
697 static void
698 NV40VPGetCondRegSwizzle(nvsFunc * shader, nvsSwzComp *swz)
699 {
700 int swzbits;
701
702 swzbits = (shader->inst[0] & NV40_VP_INST_COND_SWZ_ALL_MASK)
703 >> NV40_VP_INST_COND_SWZ_ALL_SHIFT;
704 NV20VPTXSwizzle(swzbits, swz);
705 }
706
707 static int
708 NV40VPGetCondRegID(nvsFunc * shader)
709 {
710 return ((shader->inst[0] & NV40_VP_INST_COND_REG_SELECT_1) ? 1 : 0);
711 }
712
713 static int
714 NV40VPGetBranch(nvsFunc * shader)
715 {
716 int addr;
717
718 addr = ((shader->inst[2] & NV40_VP_INST_IADDRH_MASK)
719 >> NV40_VP_INST_IADDRH_SHIFT) << 3;
720 addr |= ((shader->inst[3] & NV40_VP_INST_IADDRL_MASK)
721 >> NV40_VP_INST_IADDRL_SHIFT);
722 return addr;
723 }
724
725 void
726 NV40VPInitShaderFuncs(nvsFunc * shader)
727 {
728 /* Inherit NV30 VP code, we share some of it */
729 NV30VPInitShaderFuncs(shader);
730
731 /* Limits */
732 shader->MaxInst = 4096;
733 shader->MaxAttrib = 16;
734 shader->MaxTemp = 32;
735 shader->MaxAddress = 2;
736 shader->MaxConst = 256;
737 shader->caps = SCAP_SRC_ABS;
738
739 /* Add extra opcodes for NV40+ */
740 // MOD_OPCODE(NVVP_TX_VOP, NV40_VP_INST_OP_TXWHAT, NVS_OP_TEX , 0, 4, -1);
741 MOD_OPCODE(NVVP_TX_SOP, NV40_VP_INST_OP_PUSHA, NVS_OP_PUSHA, 3, -1, -1);
742 MOD_OPCODE(NVVP_TX_SOP, NV40_VP_INST_OP_POPA , NVS_OP_POPA , -1, -1, -1);
743
744 shader->InitInstruction = NV40VPInitInstruction;
745 shader->SupportsOpcode = NV40VPSupportsOpcode;
746 shader->SetOpcode = NV40VPSetOpcode;
747 shader->SetCCUpdate = NV40VPSetCCUpdate;
748 shader->SetCondition = NV40VPSetCondition;
749 shader->SetResult = NV40VPSetResult;
750 shader->SetSource = NV40VPSetSource;
751 shader->SetLastInst = NV40VPSetLastInst;
752 shader->SetBranchTarget = NV40VPSetBranchTarget;
753
754 shader->HasMergedInst = NV40VPHasMergedInst;
755 shader->GetOpcodeHW = NV40VPGetOpcodeHW;
756
757 shader->GetDestFile = NV40VPGetDestFile;
758 shader->GetDestID = NV40VPGetDestID;
759 shader->GetDestMask = NV40VPGetDestMask;
760
761 shader->GetSourceHW = NV40VPGetSourceHW;
762 shader->GetSourceFile = NV40VPGetSourceFile;
763 shader->GetSourceID = NV40VPGetSourceID;
764 shader->GetSourceNegate = NV40VPGetSourceNegate;
765 shader->GetSourceSwizzle = NV40VPGetSourceSwizzle;
766 shader->GetSourceIndexed = NV40VPGetSourceIndexed;
767
768 shader->GetRelAddressSwizzle = NV40VPGetAddressRegSwizzle;
769
770 shader->SupportsConditional = NV40VPSupportsConditional;
771 shader->GetConditionUpdate = NV40VPGetConditionUpdate;
772 shader->GetConditionTest = NV40VPGetConditionTest;
773 shader->GetCondition = NV40VPGetCondition;
774 shader->GetCondRegSwizzle = NV40VPGetCondRegSwizzle;
775 shader->GetCondRegID = NV40VPGetCondRegID;
776
777 shader->GetBranch = NV40VPGetBranch;
778 }