]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/qi/float.c
ip/ipconfig: format ipmask with %M instead of %I
[plan9front.git] / sys / src / cmd / qi / float.c
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <mach.h>
5 #define Extern extern
6 #include "power.h"
7
8 ulong   setfpscr(void);
9 void    setfpcc(double);
10 void    farith(ulong);
11 void    farith2(ulong);
12 void    fariths(ulong);
13 void    fcmp(ulong);
14 void    mtfsb1(ulong);
15 void    mcrfs(ulong);
16 void    mtfsb0(ulong);
17 void    mtfsf(ulong);
18 void    mtfsfi(ulong);
19 void    mffs(ulong);
20 void    mtfsf(ulong);
21
22 Inst    op59[] = {
23 [18] {fariths, "fdivs", Ifloat},
24 [20] {fariths, "fsubs", Ifloat},
25 [21] {fariths, "fadds", Ifloat},
26 [22] {unimp, "fsqrts", Ifloat},
27 [24] {unimp, "fres", Ifloat},
28 [25] {fariths, "fmuls", Ifloat},
29 [28] {fariths, "fmsubs", Ifloat},
30 [29] {fariths, "fmadds", Ifloat},
31 [30] {fariths, "fnmsubs", Ifloat},
32 [31] {fariths, "fnmadds", Ifloat},
33 };
34
35 Inset   ops59 = {op59, nelem(op59)};
36
37 Inst    op63a[] = {
38 [12] {farith, "frsp", Ifloat},
39 [14] {farith, "fctiw", Ifloat},
40 [15] {farith, "fctiwz", Ifloat},
41 [18] {farith, "fdiv", Ifloat},
42 [20] {farith, "fsub", Ifloat},
43 [21] {farith, "fadd", Ifloat},
44 [22] {unimp, "frsqrt", Ifloat},
45 [23] {unimp, "fsel", Ifloat},
46 [25] {farith, "fmul", Ifloat},
47 [26] {unimp, "frsqrte", Ifloat},
48 [28] {farith, "fmsub", Ifloat},
49 [29] {farith, "fmadd", Ifloat},
50 [30] {farith, "fnmsub", Ifloat},
51 [31] {farith, "fnmadd", Ifloat},
52 };
53
54 Inset   ops63a= {op63a, nelem(op63a)};
55
56 Inst    op63b[] = {
57 [0] {fcmp, "fcmpu", Ifloat},
58 [32] {fcmp, "fcmpo", Ifloat},
59 [38] {mtfsb1, "mtfsb1", Ifloat},
60 [40] {farith2, "fneg", Ifloat},
61 [64] {mcrfs, "mcrfs", Ifloat},
62 [70] {mtfsb0, "mtfsb0", Ifloat},
63 [72] {farith2, "fmr", Ifloat},
64 [134] {mtfsfi, "mtfsfi", Ifloat},
65 [136] {farith2, "fnabs", Ifloat},
66 [264] {farith2, "fabs", Ifloat},
67 [583] {mffs, "mffs", Ifloat},
68 [711] {mtfsf, "mtfsf", Ifloat},
69 };
70
71 Inset   ops63b = {op63b, nelem(op63b)};
72
73 void
74 fpreginit(void)
75 {
76         int i;
77
78         /* Normally initialised by the kernel */
79         reg.fd[27] = 4503601774854144.0;
80         reg.fd[29] = 0.5;
81         reg.fd[28] = 0.0;
82         reg.fd[30] = 1.0;
83         reg.fd[31] = 2.0;
84         for(i = 0; i < 27; i++)
85                 reg.fd[i] = reg.fd[28];
86 }
87
88 static double
89 v2fp(uvlong v)
90 {
91         FPdbleword f;
92
93         f.hi = v>>32;
94         f.lo = v;
95         return f.x;
96 }
97
98 static uvlong
99 fp2v(double d)
100 {
101         FPdbleword f;
102
103         f.x = d;
104         return ((uvlong)f.hi<<32) | f.lo;
105 }
106
107 void
108 lfs(ulong ir)
109 {
110         ulong ea;
111         int imm, ra, rd, upd;
112         union {
113                 ulong   i;
114                 float   f;
115         } u;
116
117         getairr(ir);
118         ea = imm;
119         upd = (ir&(1L<<26))!=0;
120         if(ra) {
121                 ea += reg.r[ra];
122                 if(upd)
123                         reg.r[ra] = ea;
124         } else {
125                 if(upd)
126                         undef(ir);
127         }
128         if(trace)
129                 itrace("%s\tf%d,%ld(r%d) ea=%lux", ci->name, rd, imm, ra, ea);
130
131         u.i = getmem_w(ea);
132         reg.fd[rd] = u.f;
133 }
134
135 void
136 lfsx(ulong ir)
137 {
138         ulong ea;
139         int rd, ra, rb, upd;
140         union {
141                 ulong   i;
142                 float   f;
143         } u;
144
145         getarrr(ir);
146         ea = reg.r[rb];
147         upd = ((ir>>1)&0x3FF)==567;
148         if(ra){
149                 ea += reg.r[ra];
150                 if(upd)
151                         reg.r[ra] = ea;
152                 if(trace)
153                         itrace("%s\tf%d,(r%d+r%d) ea=%lux", ci->name, rd, ra, rb, ea);
154         } else {
155                 if(upd)
156                         undef(ir);
157                 if(trace)
158                         itrace("%s\tf%d,(r%d) ea=%lux", ci->name, rd, rb, ea);
159         }
160
161         u.i = getmem_w(ea);
162         reg.fd[rd] = u.f;
163 }
164
165 void
166 lfd(ulong ir)
167 {
168         ulong ea;
169         int imm, ra, rd, upd;
170
171         getairr(ir);
172         ea = imm;
173         upd = (ir&(1L<<26))!=0;
174         if(ra) {
175                 ea += reg.r[ra];
176                 if(upd)
177                         reg.r[ra] = ea;
178         } else {
179                 if(upd)
180                         undef(ir);
181         }
182         if(trace)
183                 itrace("%s\tf%d,%ld(r%d) ea=%lux", ci->name, rd, imm, ra, ea);
184
185         reg.fd[rd] = v2fp(getmem_v(ea));
186 }
187
188 void
189 lfdx(ulong ir)
190 {
191         ulong ea;
192         int rd, ra, rb, upd;
193
194         getarrr(ir);
195         ea = reg.r[rb];
196         upd = ((ir>>1)&0x3FF)==631;
197         if(ra){
198                 ea += reg.r[ra];
199                 if(upd)
200                         reg.r[ra] = ea;
201                 if(trace)
202                         itrace("%s\tf%d,(r%d+r%d) ea=%lux", ci->name, rd, ra, rb, ea);
203         } else {
204                 if(upd)
205                         undef(ir);
206                 if(trace)
207                         itrace("%s\tf%d,(r%d) ea=%lux", ci->name, rd, rb, ea);
208         }
209
210         reg.fd[rd] = v2fp(getmem_v(ea));
211 }
212
213 void
214 stfs(ulong ir)
215 {
216         ulong ea;
217         int imm, ra, rd, upd;
218         union {
219                 float f;
220                 ulong w;
221         } u;
222
223         getairr(ir);
224         ea = imm;
225         upd = (ir&(1L<<26))!=0;
226         if(ra) {
227                 ea += reg.r[ra];
228                 if(upd)
229                         reg.r[ra] = ea;
230         } else {
231                 if(upd)
232                         undef(ir);
233         }
234         if(trace)
235                 itrace("%s\tf%d,%ld(r%d) %lux=%g",
236                                         ci->name, rd, imm, ra, ea, reg.fd[rd]);
237         u.f = reg.fd[rd];       /* BUG: actual PPC conversion is more subtle than this */
238         putmem_w(ea, u.w);
239 }
240
241 void
242 stfsx(ulong ir)
243 {
244         ulong ea;
245         int rd, ra, rb, upd;
246         union {
247                 float   f;
248                 ulong   w;
249         } u;
250
251         getarrr(ir);
252         ea = reg.r[rb];
253         upd = getxo(ir)==695;
254         if(ra){
255                 ea += reg.r[ra];
256                 if(upd)
257                         reg.r[ra] = ea;
258                 if(trace)
259                         itrace("%s\tf%d,(r%d+r%d) %lux=%g", ci->name, rd, ra, rb, ea, (float)reg.fd[rd]);
260         } else {
261                 if(upd)
262                         undef(ir);
263                 if(trace)
264                         itrace("%s\tf%d,(r%d) %lux=%g", ci->name, rd, rb, ea, (float)reg.fd[rd]);
265         }
266
267         u.f = reg.fd[rd];       /* BUG: actual PPC conversion is more subtle than this */
268         putmem_w(ea, u.w);
269 }
270
271 void
272 stfd(ulong ir)
273 {
274         ulong ea;
275         int imm, ra, rd, upd;
276
277         getairr(ir);
278         ea = imm;
279         upd = (ir&(1L<<26))!=0;
280         if(ra) {
281                 ea += reg.r[ra];
282                 if(upd)
283                         reg.r[ra] = ea;
284         } else {
285                 if(upd)
286                         undef(ir);
287         }
288         if(trace)
289                 itrace("%s\tf%d,%ld(r%d) %lux=%g",
290                                         ci->name, rd, imm, ra, ea, reg.fd[rd]);
291
292         putmem_v(ea, fp2v(reg.fd[rd]));
293 }
294
295 void
296 stfdx(ulong ir)
297 {
298         ulong ea;
299         int rd, ra, rb, upd;
300
301         getarrr(ir);
302         ea = reg.r[rb];
303         upd = ((ir>>1)&0x3FF)==759;
304         if(ra){
305                 ea += reg.r[ra];
306                 if(upd)
307                         reg.r[ra] = ea;
308                 if(trace)
309                         itrace("%s\tf%d,(r%d+r%d) %lux=%g", ci->name, rd, ra, rb, ea, reg.fd[rd]);
310         } else {
311                 if(upd)
312                         undef(ir);
313                 if(trace)
314                         itrace("%s\tf%d,(r%d) %lux=%g", ci->name, rd, rb, ea, reg.fd[rd]);
315         }
316
317         putmem_v(ea, fp2v(reg.fd[rd]));
318 }
319
320 void
321 mcrfs(ulong ir)
322 {
323         ulong rd, ra, rb;
324         static ulong fpscr0[] ={
325                 FPS_FX|FPS_OX,
326                 FPS_UX|FPS_ZX|FPS_XX|FPS_VXSNAN,
327                 FPS_VXISI|FPS_VXIDI|FPS_VXZDZ|FPS_VXIMZ,
328                 FPS_VXVC,
329                 0,
330                 FPS_VXCVI,
331         };
332
333         getarrr(ir);
334         if(rb || ra&3 || rd&3)
335                 undef(ir);
336         ra >>= 2;
337         rd >>= 2;
338         reg.cr = (reg.cr & ~mkCR(rd, 0xF)) | mkCR(rd, getCR(ra, reg.fpscr));
339         reg.fpscr &= ~fpscr0[ra];
340         if(trace)
341                 itrace("mcrfs\tcrf%d,crf%d\n", rd, ra);
342 }
343
344 void
345 mffs(ulong ir)
346 {
347         int rd, ra, rb;
348         FPdbleword d;
349
350         getarrr(ir);
351         if(ra || rb)
352                 undef(ir);
353         d.hi = 0xFFF80000UL;
354         d.lo = reg.fpscr;
355         reg.fd[rd] = d.x;
356         /* it's anyone's guess how CR1 should be set when ir&1 */
357         reg.cr &= ~mkCR(1, 0xE);        /* leave SO, reset others */
358         if(trace)
359                 itrace("mffs%s\tfr%d\n", ir&1?".":"", rd);
360 }
361
362 void
363 mtfsb1(ulong ir)
364 {
365         int rd, ra, rb;
366
367         getarrr(ir);
368         if(ra || rb)
369                 undef(ir);
370         reg.fpscr |= (1L << (31-rd));
371         /* BUG: should set summary bits */
372         if(ir & 1)
373                 reg.cr &= ~mkCR(1, 0xE);        /* BUG: manual unclear: leave SO, reset others? */
374         if(trace)
375                 itrace("mtfsb1%s\tfr%d\n", ir&1?".":"", rd);
376 }
377
378 void
379 mtfsb0(ulong ir)
380 {
381         int rd, ra, rb;
382
383         getarrr(ir);
384         if(ra || rb)
385                 undef(ir);
386         reg.fpscr &= ~(1L << (31-rd));
387         if(ir & 1)
388                 reg.cr &= ~mkCR(1, 0xE);                /* BUG: manual unclear: leave SO, reset others? */
389         if(trace)
390                 itrace("mtfsb0%s\tfr%d\n", ir&1?".":"", rd);
391 }
392
393 void
394 mtfsf(ulong ir)
395 {
396         int fm, rb, i;
397         FPdbleword d;
398         ulong v;
399
400         if(ir & ((1L << 25)|(1L << 16)))
401                 undef(ir);
402         rb = (ir >> 11) & 0x1F;
403         fm = (ir >> 17) & 0xFF;
404         d.x = reg.fd[rb];
405         v = d.lo;
406         for(i=0; i<8; i++)
407                 if(fm & (1 << (7-i)))
408                         reg.fpscr = (reg.fpscr & ~mkCR(i, 0xF)) | mkCR(i, getCR(i, v));
409         /* BUG: should set FEX and VX `according to the usual rule' */
410         if(ir & 1)
411                 reg.cr &= ~mkCR(1, 0xE);                /* BUG: manual unclear: leave SO, reset others? */
412         if(trace)
413                 itrace("mtfsf%s\t#%.2x,fr%d", ir&1?".":"", fm, rb);
414 }
415
416 void
417 mtfsfi(ulong ir)
418 {
419         int imm, rd;
420
421         if(ir & ((0x7F << 16)|(1L << 11)))
422                 undef(ir);
423         rd = (ir >> 23) & 0xF;
424         imm = (ir >> 12) & 0xF;
425         reg.fpscr = (reg.fpscr & ~mkCR(rd, 0xF)) | mkCR(rd, imm);
426         /* BUG: should set FEX and VX `according to the usual rule' */
427         if(ir & 1)
428                 reg.cr &= ~mkCR(1, 0xE);                /* BUG: manual unclear: leave SO, reset others? */
429         if(trace)
430                 itrace("mtfsfi%s\tcrf%d,#%x", ir&1?".":"", rd, imm);
431 }
432
433 void
434 fcmp(ulong ir)
435 {
436         int fc, rd, ra, rb;
437
438         getarrr(ir);
439         if(rd & 3)
440                 undef(ir);
441         rd >>= 2;
442         SET(fc);
443         switch(getxo(ir)) {
444         default:
445                 undef(ir);
446         case 0:
447                 if(trace)
448                         itrace("fcmpu\tcr%d,f%d,f%d", rd, ra, rb);
449                 if(isNaN(reg.fd[ra]) || isNaN(reg.fd[rb])) {
450                         fc = CRFU;
451                         break;
452                 }
453                 if(reg.fd[ra] == reg.fd[rb]) {
454                         fc = CREQ;
455                         break;
456                 }
457                 if(reg.fd[ra] < reg.fd[rb]) {
458                         fc = CRLT;
459                         break;
460                 }
461                 if(reg.fd[ra] > reg.fd[rb]) {
462                         fc = CRGT;
463                         break;
464                 }
465                 print("qi: fcmp error\n");
466                 break;
467         case 32:
468                 if(trace)
469                         itrace("fcmpo\tcr%d,f%d,f%d", rd, ra, rb);
470                 if(isNaN(reg.fd[ra]) || isNaN(reg.fd[rb])) {    /* BUG: depends whether quiet or signalling ... */
471                         fc = CRFU;
472                         Bprint(bioout, "invalid_fp_register\n");
473                         longjmp(errjmp, 0);
474                 }
475                 if(reg.fd[ra] == reg.fd[rb]) {
476                         fc = CREQ;
477                         break;
478                 }
479                 if(reg.fd[ra] < reg.fd[rb]) {
480                         fc = CRLT;
481                         break;
482                 }
483                 if(reg.fd[ra] > reg.fd[rb]) {
484                         fc = CRGT;
485                         break;
486                 }
487                 print("qi: fcmp error\n");
488                 break;
489
490         }
491         fc >>= 28;
492         reg.cr = (reg.cr & ~mkCR(rd,~0)) | mkCR(rd, fc);
493         reg.fpscr = (reg.fpscr & ~0xF800) | (fc<<11);
494         /* BUG: update FX, VXSNAN, VXVC */
495 }
496
497 /*
498  * the farith functions probably don't produce the right results
499  * in the presence of NaNs, Infs, etc., esp. wrt exception handling, 
500  */
501 void
502 fariths(ulong ir)
503 {
504         int rd, ra, rb, rc, fmt;
505         char *cc;
506         ulong fpscr;
507
508         fmt = 0;
509         rc = (ir>>6)&0x1F;
510         getarrr(ir);
511         switch(getxo(ir)&0x1F) {        /* partial XO decode */
512         default:
513                 undef(ir);
514         case 18:
515                 if((float)reg.fd[rb] == 0.0) {
516                         Bprint(bioout, "fp_exception ZX\n");
517                         reg.fpscr |= FPS_ZX | FPS_FX;
518                         longjmp(errjmp, 0);
519                 }
520                 reg.fd[rd] = (float)(reg.fd[ra] / reg.fd[rb]);
521                 break;
522         case 20:
523                 reg.fd[rd] = (float)(reg.fd[ra] - reg.fd[rb]);
524                 break;
525         case 21:
526                 reg.fd[rd] = (float)(reg.fd[ra] + reg.fd[rb]);
527                 break;
528         case 25:
529                 reg.fd[rd] = (float)(reg.fd[ra] * reg.fd[rc]);
530                 rb = rc;
531                 break;
532         case 28:
533                 reg.fd[rd] = (float)((reg.fd[ra] * reg.fd[rc]) - reg.fd[rb]);
534                 fmt = 2;
535                 break;
536         case 29:
537                 reg.fd[rd] = (float)((reg.fd[ra] * reg.fd[rc]) + reg.fd[rb]);
538                 fmt = 2;
539                 break;
540         case 30:
541                 reg.fd[rd] = (float)-((reg.fd[ra] * reg.fd[rc]) - reg.fd[rb]);
542                 fmt = 2;
543                 break;
544         case 31:
545                 reg.fd[rd] = (float)-((reg.fd[ra] * reg.fd[rc]) + reg.fd[rb]);
546                 fmt = 2;
547                 break;
548         }
549         if(fmt==1 && ra)
550                 undef(ir);
551         fpscr = setfpscr();
552         setfpcc(reg.fd[rd]);
553         cc = "";
554         if(ir & 1) {
555                 cc = ".";
556                 reg.cr = (reg.cr & ~mkCR(1, ~0)) | mkCR(1, (fpscr>>28));
557         }
558         if(trace) {
559                 switch(fmt) {
560                 case 0:
561                         itrace("%s%s\tfr%d,fr%d,fr%d", ci->name, cc, rd, ra, rb);
562                         break;
563                 case 1:
564                         itrace("%s%s\tfr%d,fr%d", ci->name, cc, rd, rb);
565                         break;
566                 case 2:
567                         itrace("%s%s\tfr%d,fr%d,fr%d,fr%d", ci->name, cc, rd, ra, rc, rb);
568                         break;
569                 }
570         }
571 }
572
573 void
574 farith(ulong ir)
575 {
576         vlong vl;
577         int rd, ra, rb, rc, fmt;
578         char *cc;
579         ulong fpscr;
580         int nocc;
581         double d;
582
583         fmt = 0;
584         nocc = 0;
585         rc = (ir>>6)&0x1F;
586         getarrr(ir);
587         switch(getxo(ir)&0x1F) { /* partial XO decode */
588         default:
589                 undef(ir);
590         case 12:        /* frsp */
591                 reg.fd[rd] = (float)reg.fd[rb];
592                 fmt = 1;
593                 break;
594         case 14:        /* fctiw */     /* BUG: ignores rounding mode */
595         case 15:        /* fctiwz */
596                 d = reg.fd[rb];
597                 if(d >= 0x7fffffff)
598                         vl = 0x7fffffff;
599                 else if(d < 0x80000000)
600                         vl = 0x80000000;
601                 else
602                         vl = d;
603                 reg.fd[rd] = v2fp(vl);
604                 fmt = 1;
605                 nocc = 1;
606                 break;
607         case 18:
608                 if(reg.fd[rb] == 0.0) {
609                         Bprint(bioout, "fp_exception ZX\n");
610                         reg.fpscr |= FPS_ZX | FPS_FX;
611                         longjmp(errjmp, 0);
612                 }
613                 reg.fd[rd] = reg.fd[ra] / reg.fd[rb];
614                 break;
615         case 20:
616                 reg.fd[rd] = reg.fd[ra] - reg.fd[rb];
617                 break;
618         case 21:
619                 reg.fd[rd] = reg.fd[ra] + reg.fd[rb];
620                 break;
621         case 25:
622                 reg.fd[rd] = reg.fd[ra] * reg.fd[rc];
623                 rb = rc;
624                 break;
625         case 28:
626                 reg.fd[rd] = (reg.fd[ra] * reg.fd[rc]) - reg.fd[rb];
627                 fmt = 2;
628                 break;
629         case 29:
630                 reg.fd[rd] = (reg.fd[ra] * reg.fd[rc]) + reg.fd[rb];
631                 fmt = 2;
632                 break;
633         case 30:
634                 reg.fd[rd] = -((reg.fd[ra] * reg.fd[rc]) - reg.fd[rb]);
635                 fmt = 2;
636                 break;
637         case 31:
638                 reg.fd[rd] = -((reg.fd[ra] * reg.fd[rc]) + reg.fd[rb]);
639                 fmt = 2;
640                 break;
641         }
642         if(fmt==1 && ra)
643                 undef(ir);
644         fpscr = setfpscr();
645         if(nocc == 0)
646                 setfpcc(reg.fd[rd]);
647         cc = "";
648         if(ir & 1) {
649                 cc = ".";
650                 reg.cr = (reg.cr & ~mkCR(1, ~0)) | mkCR(1, (fpscr>>28));
651         }
652         if(trace) {
653                 switch(fmt) {
654                 case 0:
655                         itrace("%s%s\tfr%d,fr%d,fr%d", ci->name, cc, rd, ra, rb);
656                         break;
657                 case 1:
658                         itrace("%s%s\tfr%d,fr%d", ci->name, cc, rd, rb);
659                         break;
660                 case 2:
661                         itrace("%s%s\tfr%d,fr%d,fr%d,fr%d", ci->name, cc, rd, ra, rc, rb);
662                         break;
663                 }
664         }
665 }
666
667 void
668 farith2(ulong ir)
669 {
670         int rd, ra, rb;
671         char *cc;
672         ulong fpscr;
673
674         getarrr(ir);
675         switch(getxo(ir)) { /* full XO decode */
676         default:
677                 undef(ir);
678         case 40:
679                 reg.fd[rd] = -reg.fd[rb];
680                 break;
681         case 72:
682                 reg.fd[rd] = reg.fd[rb];
683                 break;
684         case 136:
685                 reg.fd[rd] = -fabs(reg.fd[rb]);
686                 break;
687         case 264:
688                 reg.fd[rd] = fabs(reg.fd[rb]);
689                 break;
690         }
691         if(ra)
692                 undef(ir);
693         fpscr = setfpscr();
694         setfpcc(reg.fd[rd]);
695         cc = "";
696         if(ir & 1) {
697                 cc = ".";
698                 reg.cr = (reg.cr & ~mkCR(1, ~0)) | mkCR(1, (fpscr>>28));
699         }
700         if(trace)
701                 itrace("%s%s\tfr%d,fr%d", ci->name, cc, rd, rb);
702 }
703
704 ulong
705 setfpscr(void)
706 {
707         ulong fps, fpscr;
708
709         fps = getfsr();
710         fpscr = reg.fpscr;
711         if(fps & FPAOVFL)
712                 fpscr |= FPS_OX;
713         if(fps & FPAINEX)
714                 fpscr |= FPS_XX;
715         if(fps & FPAUNFL)
716                 fpscr |= FPS_UX;
717         if(fps & FPAZDIV)
718                 fpscr |= FPS_ZX;
719         if(fpscr != reg.fpscr) {
720                 fpscr |= FPS_FX;
721                 reg.fpscr = fpscr;
722         }
723         return fpscr;
724 }
725
726 void
727 setfpcc(double r)
728 {
729         int c;
730
731         c = 0;
732         if(r == 0)
733                 c |= 2;
734         else if(r < 0)
735                 c |= 4;
736         else
737                 c |= 8;
738         if(isNaN(r))
739                 c |= 1;
740         reg.fpscr = (reg.fpscr & ~0xF800) | (0<<15) | (c<<11); /* unsure about class bit */
741 }