1 /**********************************************************
2 * Copyright 2008-2009 VMware, Inc. All rights reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without
7 * restriction, including without limitation the rights to use, copy,
8 * modify, merge, publish, distribute, sublicense, and/or sell copies
9 * of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 *
24 **********************************************************/
25
26 /**
27 * @file
28 * SVGA Shader Dump Facilities
29 *
30 * @author Michal Krol <michal@vmware.com>
31 */
32
33 #include <assert.h>
34 #include <string.h>
35
36 #include "svga_shader.h"
37 #include "svga_shader_dump.h"
38 #include "svga_shader_op.h"
39 #include "util/u_debug.h"
40
41 #include "../svga_hw_reg.h"
42 #include "svga3d_shaderdefs.h"
43
44 struct dump_info
45 {
46 uint32 version;
47 boolean is_ps;
48 int indent;
49 };
50
51 #define DUMP_MAX_OP_SRC 4
52
53 struct dump_op
54 {
55 struct sh_op op;
56 struct sh_dstreg dst;
57 struct sh_srcreg dstind;
58 struct sh_srcreg src[DUMP_MAX_OP_SRC];
59 struct sh_srcreg srcind[DUMP_MAX_OP_SRC];
60 struct sh_srcreg p0;
61 };
62
63 static void
dump_indent(int indent)64 dump_indent(int indent)
65 {
66 int i;
67
68 for (i = 0; i < indent; ++i) {
69 _debug_printf(" ");
70 }
71 }
72
dump_op(struct sh_op op,const char * mnemonic)73 static void dump_op( struct sh_op op, const char *mnemonic )
74 {
75 assert( op.is_reg == 0 );
76
77 if (op.predicated) {
78 _debug_printf("(p0) ");
79 }
80 if (op.coissue)
81 _debug_printf( "+" );
82 _debug_printf( "%s", mnemonic );
83
84 switch (op.opcode) {
85 case SVGA3DOP_TEX:
86 switch (op.control) {
87 case 0:
88 break;
89 case 1 /* PROJECT */:
90 _debug_printf("p");
91 break;
92 case 2 /* BIAS */:
93 _debug_printf("b");
94 break;
95 default:
96 assert(0);
97 }
98 break;
99
100 case SVGA3DOP_IFC:
101 case SVGA3DOP_BREAKC:
102 case SVGA3DOP_SETP:
103 switch (op.control) {
104 case SVGA3DOPCOMP_GT:
105 _debug_printf("_gt");
106 break;
107 case SVGA3DOPCOMP_EQ:
108 _debug_printf("_eq");
109 break;
110 case SVGA3DOPCOMP_GE:
111 _debug_printf("_ge");
112 break;
113 case SVGA3DOPCOMP_LT:
114 _debug_printf("_lt");
115 break;
116 case SVGA3DOPCOMPC_NE:
117 _debug_printf("_ne");
118 break;
119 case SVGA3DOPCOMP_LE:
120 _debug_printf("_le");
121 break;
122 default:
123 assert(0);
124 }
125 break;
126
127 default:
128 assert(op.control == 0);
129 }
130 }
131
132 static void
format_reg(const char * name,const struct sh_reg reg,const struct sh_srcreg * indreg)133 format_reg(const char *name,
134 const struct sh_reg reg,
135 const struct sh_srcreg *indreg)
136 {
137 if (reg.relative) {
138 assert(indreg);
139
140 if (sh_srcreg_type(*indreg) == SVGA3DREG_LOOP) {
141 _debug_printf("%s[aL+%u]", name, reg.number);
142 } else {
143 _debug_printf("%s[a%u.x+%u]", name, indreg->number, reg.number);
144 }
145 } else {
146 _debug_printf("%s%u", name, reg.number);
147 }
148 }
149
dump_reg(struct sh_reg reg,struct sh_srcreg * indreg,const struct dump_info * di)150 static void dump_reg( struct sh_reg reg, struct sh_srcreg *indreg, const struct dump_info *di )
151 {
152 assert( reg.is_reg == 1 );
153
154 switch (sh_reg_type( reg )) {
155 case SVGA3DREG_TEMP:
156 format_reg("r", reg, NULL);
157 break;
158
159 case SVGA3DREG_INPUT:
160 format_reg("v", reg, indreg);
161 break;
162
163 case SVGA3DREG_CONST:
164 format_reg("c", reg, indreg);
165 break;
166
167 case SVGA3DREG_ADDR: /* VS */
168 /* SVGA3DREG_TEXTURE */ /* PS */
169 assert(!reg.relative);
170 if (di->is_ps) {
171 format_reg("t", reg, NULL);
172 } else {
173 format_reg("a", reg, NULL);
174 }
175 break;
176
177 case SVGA3DREG_RASTOUT:
178 assert(!reg.relative);
179 switch (reg.number) {
180 case 0 /*POSITION*/:
181 _debug_printf( "oPos" );
182 break;
183 case 1 /*FOG*/:
184 _debug_printf( "oFog" );
185 break;
186 case 2 /*POINT_SIZE*/:
187 _debug_printf( "oPts" );
188 break;
189 default:
190 assert( 0 );
191 _debug_printf( "???" );
192 }
193 break;
194
195 case SVGA3DREG_ATTROUT:
196 assert( reg.number < 2 );
197 format_reg("oD", reg, NULL);
198 break;
199
200 case SVGA3DREG_TEXCRDOUT: /* VS */
201 /* SVGA3DREG_OUTPUT */ /* VS3.0+ */
202 if (!di->is_ps && di->version >= SVGA3D_VS_30) {
203 format_reg("o", reg, indreg);
204 } else {
205 format_reg("oT", reg, NULL);
206 }
207 break;
208
209 case SVGA3DREG_COLOROUT:
210 format_reg("oC", reg, NULL);
211 break;
212
213 case SVGA3DREG_DEPTHOUT:
214 assert(!reg.relative);
215 assert(reg.number == 0);
216 _debug_printf("oDepth");
217 break;
218
219 case SVGA3DREG_SAMPLER:
220 format_reg("s", reg, NULL);
221 break;
222
223 case SVGA3DREG_CONSTBOOL:
224 format_reg("b", reg, NULL);
225 break;
226
227 case SVGA3DREG_CONSTINT:
228 format_reg("i", reg, NULL);
229 break;
230
231 case SVGA3DREG_LOOP:
232 assert(!reg.relative);
233 assert( reg.number == 0 );
234 _debug_printf( "aL" );
235 break;
236
237 case SVGA3DREG_MISCTYPE:
238 assert(!reg.relative);
239 switch (reg.number) {
240 case SVGA3DMISCREG_POSITION:
241 _debug_printf("vPos");
242 break;
243 case SVGA3DMISCREG_FACE:
244 _debug_printf("vFace");
245 break;
246 default:
247 assert(0);
248 _debug_printf("???");
249 }
250 break;
251
252 case SVGA3DREG_LABEL:
253 format_reg("l", reg, NULL);
254 break;
255
256 case SVGA3DREG_PREDICATE:
257 format_reg("p", reg, NULL);
258 break;
259
260 default:
261 assert( 0 );
262 _debug_printf( "???" );
263 }
264 }
265
dump_cdata(struct sh_cdata cdata)266 static void dump_cdata( struct sh_cdata cdata )
267 {
268 _debug_printf( "%f, %f, %f, %f", cdata.xyzw[0], cdata.xyzw[1], cdata.xyzw[2], cdata.xyzw[3] );
269 }
270
dump_idata(struct sh_idata idata)271 static void dump_idata( struct sh_idata idata )
272 {
273 _debug_printf( "%d, %d, %d, %d", idata.xyzw[0], idata.xyzw[1], idata.xyzw[2], idata.xyzw[3] );
274 }
275
dump_bdata(boolean bdata)276 static void dump_bdata( boolean bdata )
277 {
278 _debug_printf( bdata ? "TRUE" : "FALSE" );
279 }
280
281 static void
dump_sampleinfo(struct sh_sampleinfo sampleinfo)282 dump_sampleinfo(struct sh_sampleinfo sampleinfo)
283 {
284 assert( sampleinfo.is_reg == 1 );
285
286 switch (sampleinfo.texture_type) {
287 case SVGA3DSAMP_2D:
288 _debug_printf( "_2d" );
289 break;
290 case SVGA3DSAMP_2D_SHADOW:
291 _debug_printf( "_2dshadow" );
292 break;
293 case SVGA3DSAMP_CUBE:
294 _debug_printf( "_cube" );
295 break;
296 case SVGA3DSAMP_VOLUME:
297 _debug_printf( "_volume" );
298 break;
299 default:
300 assert( 0 );
301 }
302 }
303
304 static void
dump_semantic(uint usage,uint usage_index)305 dump_semantic(uint usage,
306 uint usage_index)
307 {
308 switch (usage) {
309 case SVGA3D_DECLUSAGE_POSITION:
310 _debug_printf("_position");
311 break;
312 case SVGA3D_DECLUSAGE_BLENDWEIGHT:
313 _debug_printf("_blendweight");
314 break;
315 case SVGA3D_DECLUSAGE_BLENDINDICES:
316 _debug_printf("_blendindices");
317 break;
318 case SVGA3D_DECLUSAGE_NORMAL:
319 _debug_printf("_normal");
320 break;
321 case SVGA3D_DECLUSAGE_PSIZE:
322 _debug_printf("_psize");
323 break;
324 case SVGA3D_DECLUSAGE_TEXCOORD:
325 _debug_printf("_texcoord");
326 break;
327 case SVGA3D_DECLUSAGE_TANGENT:
328 _debug_printf("_tangent");
329 break;
330 case SVGA3D_DECLUSAGE_BINORMAL:
331 _debug_printf("_binormal");
332 break;
333 case SVGA3D_DECLUSAGE_TESSFACTOR:
334 _debug_printf("_tessfactor");
335 break;
336 case SVGA3D_DECLUSAGE_POSITIONT:
337 _debug_printf("_positiont");
338 break;
339 case SVGA3D_DECLUSAGE_COLOR:
340 _debug_printf("_color");
341 break;
342 case SVGA3D_DECLUSAGE_FOG:
343 _debug_printf("_fog");
344 break;
345 case SVGA3D_DECLUSAGE_DEPTH:
346 _debug_printf("_depth");
347 break;
348 case SVGA3D_DECLUSAGE_SAMPLE:
349 _debug_printf("_sample");
350 break;
351 default:
352 assert(!"Unknown usage");
353 _debug_printf("_???");
354 }
355
356 if (usage_index) {
357 _debug_printf("%u", usage_index);
358 }
359 }
360
361 static void
dump_dstreg(struct sh_dstreg dstreg,struct sh_srcreg * indreg,const struct dump_info * di)362 dump_dstreg(struct sh_dstreg dstreg,
363 struct sh_srcreg *indreg,
364 const struct dump_info *di)
365 {
366 union {
367 struct sh_reg reg;
368 struct sh_dstreg dstreg;
369 } u;
370
371 memset(&u, 0, sizeof(u));
372
373 assert( (dstreg.modifier & (SVGA3DDSTMOD_SATURATE | SVGA3DDSTMOD_PARTIALPRECISION)) == dstreg.modifier );
374
375 if (dstreg.modifier & SVGA3DDSTMOD_SATURATE)
376 _debug_printf( "_sat" );
377 if (dstreg.modifier & SVGA3DDSTMOD_PARTIALPRECISION)
378 _debug_printf( "_pp" );
379 switch (dstreg.shift_scale) {
380 case 0:
381 break;
382 case 1:
383 _debug_printf( "_x2" );
384 break;
385 case 2:
386 _debug_printf( "_x4" );
387 break;
388 case 3:
389 _debug_printf( "_x8" );
390 break;
391 case 13:
392 _debug_printf( "_d8" );
393 break;
394 case 14:
395 _debug_printf( "_d4" );
396 break;
397 case 15:
398 _debug_printf( "_d2" );
399 break;
400 default:
401 assert( 0 );
402 }
403 _debug_printf( " " );
404
405 u.dstreg = dstreg;
406 dump_reg( u.reg, indreg, di);
407 if (dstreg.write_mask != SVGA3DWRITEMASK_ALL) {
408 _debug_printf( "." );
409 if (dstreg.write_mask & SVGA3DWRITEMASK_0)
410 _debug_printf( "x" );
411 if (dstreg.write_mask & SVGA3DWRITEMASK_1)
412 _debug_printf( "y" );
413 if (dstreg.write_mask & SVGA3DWRITEMASK_2)
414 _debug_printf( "z" );
415 if (dstreg.write_mask & SVGA3DWRITEMASK_3)
416 _debug_printf( "w" );
417 }
418 }
419
dump_srcreg(struct sh_srcreg srcreg,struct sh_srcreg * indreg,const struct dump_info * di)420 static void dump_srcreg( struct sh_srcreg srcreg, struct sh_srcreg *indreg, const struct dump_info *di )
421 {
422 struct sh_reg srcreg_sh = {0};
423 /* bit-fields carefully aligned, ensure they stay that way. */
424 STATIC_ASSERT(sizeof(struct sh_reg) == sizeof(struct sh_srcreg));
425 memcpy(&srcreg_sh, &srcreg, sizeof(srcreg_sh));
426
427 switch (srcreg.modifier) {
428 case SVGA3DSRCMOD_NEG:
429 case SVGA3DSRCMOD_BIASNEG:
430 case SVGA3DSRCMOD_SIGNNEG:
431 case SVGA3DSRCMOD_X2NEG:
432 case SVGA3DSRCMOD_ABSNEG:
433 _debug_printf( "-" );
434 break;
435 case SVGA3DSRCMOD_COMP:
436 _debug_printf( "1-" );
437 break;
438 case SVGA3DSRCMOD_NOT:
439 _debug_printf( "!" );
440 }
441 dump_reg(srcreg_sh, indreg, di );
442 switch (srcreg.modifier) {
443 case SVGA3DSRCMOD_NONE:
444 case SVGA3DSRCMOD_NEG:
445 case SVGA3DSRCMOD_COMP:
446 case SVGA3DSRCMOD_NOT:
447 break;
448 case SVGA3DSRCMOD_BIAS:
449 case SVGA3DSRCMOD_BIASNEG:
450 _debug_printf( "_bias" );
451 break;
452 case SVGA3DSRCMOD_SIGN:
453 case SVGA3DSRCMOD_SIGNNEG:
454 _debug_printf( "_bx2" );
455 break;
456 case SVGA3DSRCMOD_X2:
457 case SVGA3DSRCMOD_X2NEG:
458 _debug_printf( "_x2" );
459 break;
460 case SVGA3DSRCMOD_DZ:
461 _debug_printf( "_dz" );
462 break;
463 case SVGA3DSRCMOD_DW:
464 _debug_printf( "_dw" );
465 break;
466 case SVGA3DSRCMOD_ABS:
467 case SVGA3DSRCMOD_ABSNEG:
468 _debug_printf("_abs");
469 break;
470 default:
471 assert( 0 );
472 }
473 if (srcreg.swizzle_x != 0 || srcreg.swizzle_y != 1 || srcreg.swizzle_z != 2 || srcreg.swizzle_w != 3) {
474 _debug_printf( "." );
475 if (srcreg.swizzle_x == srcreg.swizzle_y && srcreg.swizzle_y == srcreg.swizzle_z && srcreg.swizzle_z == srcreg.swizzle_w) {
476 _debug_printf( "%c", "xyzw"[srcreg.swizzle_x] );
477 }
478 else {
479 _debug_printf( "%c", "xyzw"[srcreg.swizzle_x] );
480 _debug_printf( "%c", "xyzw"[srcreg.swizzle_y] );
481 _debug_printf( "%c", "xyzw"[srcreg.swizzle_z] );
482 _debug_printf( "%c", "xyzw"[srcreg.swizzle_w] );
483 }
484 }
485 }
486
487 static void
parse_op(struct dump_info * di,const uint ** token,struct dump_op * op,uint num_dst,uint num_src)488 parse_op(struct dump_info *di,
489 const uint **token,
490 struct dump_op *op,
491 uint num_dst,
492 uint num_src)
493 {
494 uint i;
495
496 assert(num_dst <= 1);
497 assert(num_src <= DUMP_MAX_OP_SRC);
498
499 op->op = *(struct sh_op *)*token;
500 *token += sizeof(struct sh_op) / sizeof(uint);
501
502 if (num_dst >= 1) {
503 op->dst = *(struct sh_dstreg *)*token;
504 *token += sizeof(struct sh_dstreg) / sizeof(uint);
505 if (op->dst.relative &&
506 (!di->is_ps && di->version >= SVGA3D_VS_30)) {
507 op->dstind = *(struct sh_srcreg *)*token;
508 *token += sizeof(struct sh_srcreg) / sizeof(uint);
509 }
510 }
511
512 if (op->op.predicated) {
513 op->p0 = *(struct sh_srcreg *)*token;
514 *token += sizeof(struct sh_srcreg) / sizeof(uint);
515 }
516
517 for (i = 0; i < num_src; ++i) {
518 op->src[i] = *(struct sh_srcreg *)*token;
519 *token += sizeof(struct sh_srcreg) / sizeof(uint);
520 if (op->src[i].relative &&
521 ((!di->is_ps && di->version >= SVGA3D_VS_20) ||
522 (di->is_ps && di->version >= SVGA3D_PS_30))) {
523 op->srcind[i] = *(struct sh_srcreg *)*token;
524 *token += sizeof(struct sh_srcreg) / sizeof(uint);
525 }
526 }
527 }
528
529 static void
dump_inst(struct dump_info * di,const unsigned ** assem,struct sh_op op,const struct sh_opcode_info * info)530 dump_inst(struct dump_info *di,
531 const unsigned **assem,
532 struct sh_op op,
533 const struct sh_opcode_info *info)
534 {
535 struct dump_op dop;
536 boolean not_first_arg = FALSE;
537 uint i;
538
539 assert(info->num_dst <= 1);
540
541 di->indent -= info->pre_dedent;
542 dump_indent(di->indent);
543 di->indent += info->post_indent;
544
545 dump_op(op, info->mnemonic);
546
547 parse_op(di, assem, &dop, info->num_dst, info->num_src);
548 if (info->num_dst > 0) {
549 dump_dstreg(dop.dst, &dop.dstind, di);
550 not_first_arg = TRUE;
551 }
552
553 for (i = 0; i < info->num_src; i++) {
554 if (not_first_arg) {
555 _debug_printf(", ");
556 } else {
557 _debug_printf(" ");
558 }
559 dump_srcreg(dop.src[i], &dop.srcind[i], di);
560 not_first_arg = TRUE;
561 }
562
563 _debug_printf("\n");
564 }
565
566 void
svga_shader_dump(const unsigned * assem,unsigned dwords,unsigned do_binary)567 svga_shader_dump(
568 const unsigned *assem,
569 unsigned dwords,
570 unsigned do_binary )
571 {
572 boolean finished = FALSE;
573 struct dump_info di;
574
575 di.version = *assem++;
576 di.is_ps = (di.version & 0xFFFF0000) == 0xFFFF0000;
577 di.indent = 0;
578
579 _debug_printf(
580 "%s_%u_%u\n",
581 di.is_ps ? "ps" : "vs",
582 (di.version >> 8) & 0xff,
583 di.version & 0xff );
584
585 while (!finished) {
586 struct sh_op op = *(struct sh_op *) assem;
587
588 switch (op.opcode) {
589 case SVGA3DOP_DCL:
590 {
591 struct sh_dcl dcl = *(struct sh_dcl *) assem;
592
593 _debug_printf( "dcl" );
594 switch (sh_dstreg_type(dcl.reg)) {
595 case SVGA3DREG_INPUT:
596 if ((di.is_ps && di.version >= SVGA3D_PS_30) ||
597 (!di.is_ps && di.version >= SVGA3D_VS_30)) {
598 dump_semantic(dcl.u.semantic.usage,
599 dcl.u.semantic.usage_index);
600 }
601 break;
602 case SVGA3DREG_TEXCRDOUT:
603 if (!di.is_ps && di.version >= SVGA3D_VS_30) {
604 dump_semantic(dcl.u.semantic.usage,
605 dcl.u.semantic.usage_index);
606 }
607 break;
608 case SVGA3DREG_SAMPLER:
609 dump_sampleinfo( dcl.u.sampleinfo );
610 break;
611 }
612 dump_dstreg(dcl.reg, NULL, &di);
613 _debug_printf( "\n" );
614 assem += sizeof( struct sh_dcl ) / sizeof( unsigned );
615 }
616 break;
617
618 case SVGA3DOP_DEFB:
619 {
620 struct sh_defb defb = *(struct sh_defb *) assem;
621
622 _debug_printf( "defb " );
623 dump_reg( defb.reg, NULL, &di );
624 _debug_printf( ", " );
625 dump_bdata( defb.data );
626 _debug_printf( "\n" );
627 assem += sizeof( struct sh_defb ) / sizeof( unsigned );
628 }
629 break;
630
631 case SVGA3DOP_DEFI:
632 {
633 struct sh_defi defi = *(struct sh_defi *) assem;
634
635 _debug_printf( "defi " );
636 dump_reg( defi.reg, NULL, &di );
637 _debug_printf( ", " );
638 dump_idata( defi.idata );
639 _debug_printf( "\n" );
640 assem += sizeof( struct sh_defi ) / sizeof( unsigned );
641 }
642 break;
643
644 case SVGA3DOP_TEXCOORD:
645 {
646 struct sh_opcode_info info = *svga_opcode_info(op.opcode);
647
648 assert(di.is_ps);
649 if (di.version > SVGA3D_PS_13) {
650 assert(info.num_src == 0);
651
652 info.num_src = 1;
653 }
654
655 dump_inst(&di, &assem, op, &info);
656 }
657 break;
658
659 case SVGA3DOP_TEX:
660 {
661 struct sh_opcode_info info = *svga_opcode_info(op.opcode);
662
663 assert(di.is_ps);
664 if (di.version > SVGA3D_PS_13) {
665 assert(info.num_src == 0);
666
667 if (di.version > SVGA3D_PS_14) {
668 info.num_src = 2;
669 info.mnemonic = "texld";
670 } else {
671 info.num_src = 1;
672 }
673 }
674
675 dump_inst(&di, &assem, op, &info);
676 }
677 break;
678
679 case SVGA3DOP_DEF:
680 {
681 struct sh_def def = *(struct sh_def *) assem;
682
683 _debug_printf( "def " );
684 dump_reg( def.reg, NULL, &di );
685 _debug_printf( ", " );
686 dump_cdata( def.cdata );
687 _debug_printf( "\n" );
688 assem += sizeof( struct sh_def ) / sizeof( unsigned );
689 }
690 break;
691
692 case SVGA3DOP_SINCOS:
693 {
694 struct sh_opcode_info info = *svga_opcode_info(op.opcode);
695
696 if ((di.is_ps && di.version >= SVGA3D_PS_30) ||
697 (!di.is_ps && di.version >= SVGA3D_VS_30)) {
698 assert(info.num_src == 3);
699
700 info.num_src = 1;
701 }
702
703 dump_inst(&di, &assem, op, &info);
704 }
705 break;
706
707 case SVGA3DOP_PHASE:
708 _debug_printf( "phase\n" );
709 assem += sizeof( struct sh_op ) / sizeof( unsigned );
710 break;
711
712 case SVGA3DOP_COMMENT:
713 {
714 struct sh_comment comment = *(struct sh_comment *)assem;
715
716 /* Ignore comment contents. */
717 assem += sizeof(struct sh_comment) / sizeof(unsigned) + comment.size;
718 }
719 break;
720
721 case SVGA3DOP_END:
722 finished = TRUE;
723 break;
724
725 default:
726 {
727 const struct sh_opcode_info *info = svga_opcode_info(op.opcode);
728
729 dump_inst(&di, &assem, op, info);
730 }
731 }
732 }
733 }
734