1// 2// r_edgea.s 3// x86 assembly-language edge-processing code. 4// 5 6#include "qasm.h" 7 8#if id386 9 10 .data 11Ltemp: .long 0 12float_1_div_0100000h: .long 0x35800000 // 1.0/(float)0x100000 13float_point_999: .single 0.999 14float_1_point_001: .single 1.001 15 16 .text 17 18//-------------------------------------------------------------------- 19 20#define edgestoadd 4+8 // note odd stack offsets because of interleaving 21#define edgelist 8+12 // with pushes 22 23.globl C(R_EdgeCodeStart) 24C(R_EdgeCodeStart): 25 26.globl C(R_InsertNewEdges) 27C(R_InsertNewEdges): 28 pushl %edi 29 pushl %esi // preserve register variables 30 movl edgestoadd(%esp),%edx 31 pushl %ebx 32 movl edgelist(%esp),%ecx 33 34LDoNextEdge: 35 movl et_u(%edx),%eax 36 movl %edx,%edi 37 38LContinueSearch: 39 movl et_u(%ecx),%ebx 40 movl et_next(%ecx),%esi 41 cmpl %ebx,%eax 42 jle LAddedge 43 movl et_u(%esi),%ebx 44 movl et_next(%esi),%ecx 45 cmpl %ebx,%eax 46 jle LAddedge2 47 movl et_u(%ecx),%ebx 48 movl et_next(%ecx),%esi 49 cmpl %ebx,%eax 50 jle LAddedge 51 movl et_u(%esi),%ebx 52 movl et_next(%esi),%ecx 53 cmpl %ebx,%eax 54 jg LContinueSearch 55 56LAddedge2: 57 movl et_next(%edx),%edx 58 movl et_prev(%esi),%ebx 59 movl %esi,et_next(%edi) 60 movl %ebx,et_prev(%edi) 61 movl %edi,et_next(%ebx) 62 movl %edi,et_prev(%esi) 63 movl %esi,%ecx 64 65 cmpl $0,%edx 66 jnz LDoNextEdge 67 jmp LDone 68 69 .align 4 70LAddedge: 71 movl et_next(%edx),%edx 72 movl et_prev(%ecx),%ebx 73 movl %ecx,et_next(%edi) 74 movl %ebx,et_prev(%edi) 75 movl %edi,et_next(%ebx) 76 movl %edi,et_prev(%ecx) 77 78 cmpl $0,%edx 79 jnz LDoNextEdge 80 81LDone: 82 popl %ebx // restore register variables 83 popl %esi 84 popl %edi 85 86 ret 87 88//-------------------------------------------------------------------- 89 90#define predge 4+4 91 92.globl C(R_RemoveEdges) 93C(R_RemoveEdges): 94 pushl %ebx 95 movl predge(%esp),%eax 96 97Lre_loop: 98 movl et_next(%eax),%ecx 99 movl et_nextremove(%eax),%ebx 100 movl et_prev(%eax),%edx 101 testl %ebx,%ebx 102 movl %edx,et_prev(%ecx) 103 jz Lre_done 104 movl %ecx,et_next(%edx) 105 106 movl et_next(%ebx),%ecx 107 movl et_prev(%ebx),%edx 108 movl et_nextremove(%ebx),%eax 109 movl %edx,et_prev(%ecx) 110 testl %eax,%eax 111 movl %ecx,et_next(%edx) 112 jnz Lre_loop 113 114 popl %ebx 115 ret 116 117Lre_done: 118 movl %ecx,et_next(%edx) 119 popl %ebx 120 121 ret 122 123//-------------------------------------------------------------------- 124 125#define pedgelist 4+4 // note odd stack offset because of interleaving 126 // with pushes 127 128.globl C(R_StepActiveU) 129C(R_StepActiveU): 130 pushl %edi 131 movl pedgelist(%esp),%edx 132 pushl %esi // preserve register variables 133 pushl %ebx 134 135 movl et_prev(%edx),%esi 136 137LNewEdge: 138 movl et_u(%esi),%edi 139 140LNextEdge: 141 movl et_u(%edx),%eax 142 movl et_u_step(%edx),%ebx 143 addl %ebx,%eax 144 movl et_next(%edx),%esi 145 movl %eax,et_u(%edx) 146 cmpl %edi,%eax 147 jl LPushBack 148 149 movl et_u(%esi),%edi 150 movl et_u_step(%esi),%ebx 151 addl %ebx,%edi 152 movl et_next(%esi),%edx 153 movl %edi,et_u(%esi) 154 cmpl %eax,%edi 155 jl LPushBack2 156 157 movl et_u(%edx),%eax 158 movl et_u_step(%edx),%ebx 159 addl %ebx,%eax 160 movl et_next(%edx),%esi 161 movl %eax,et_u(%edx) 162 cmpl %edi,%eax 163 jl LPushBack 164 165 movl et_u(%esi),%edi 166 movl et_u_step(%esi),%ebx 167 addl %ebx,%edi 168 movl et_next(%esi),%edx 169 movl %edi,et_u(%esi) 170 cmpl %eax,%edi 171 jnl LNextEdge 172 173LPushBack2: 174 movl %edx,%ebx 175 movl %edi,%eax 176 movl %esi,%edx 177 movl %ebx,%esi 178 179LPushBack: 180// push it back to keep it sorted 181 movl et_prev(%edx),%ecx 182 movl et_next(%edx),%ebx 183 184// done if the -1 in edge_aftertail triggered this 185 cmpl $(C(edge_aftertail)),%edx 186 jz LUDone 187 188// pull the edge out of the edge list 189 movl et_prev(%ecx),%edi 190 movl %ecx,et_prev(%esi) 191 movl %ebx,et_next(%ecx) 192 193// find out where the edge goes in the edge list 194LPushBackLoop: 195 movl et_prev(%edi),%ecx 196 movl et_u(%edi),%ebx 197 cmpl %ebx,%eax 198 jnl LPushBackFound 199 200 movl et_prev(%ecx),%edi 201 movl et_u(%ecx),%ebx 202 cmpl %ebx,%eax 203 jl LPushBackLoop 204 205 movl %ecx,%edi 206 207// put the edge back into the edge list 208LPushBackFound: 209 movl et_next(%edi),%ebx 210 movl %edi,et_prev(%edx) 211 movl %ebx,et_next(%edx) 212 movl %edx,et_next(%edi) 213 movl %edx,et_prev(%ebx) 214 215 movl %esi,%edx 216 movl et_prev(%esi),%esi 217 218 cmpl $(C(edge_tail)),%edx 219 jnz LNewEdge 220 221LUDone: 222 popl %ebx // restore register variables 223 popl %esi 224 popl %edi 225 226 ret 227 228//-------------------------------------------------------------------- 229 230#define surf 4 // note this is loaded before any pushes 231 232 .align 4 233TrailingEdge: 234 movl st_spanstate(%esi),%eax // check for edge inversion 235 decl %eax 236 jnz LInverted 237 238 movl %eax,st_spanstate(%esi) 239 movl st_insubmodel(%esi),%ecx 240 movl 0x12345678,%edx // surfaces[1].st_next 241LPatch0: 242 movl C(r_bmodelactive),%eax 243 subl %ecx,%eax 244 cmpl %esi,%edx 245 movl %eax,C(r_bmodelactive) 246 jnz LNoEmit // surface isn't on top, just remove 247 248// emit a span (current top going away) 249 movl et_u(%ebx),%eax 250 shrl $20,%eax // iu = integral pixel u 251 movl st_last_u(%esi),%edx 252 movl st_next(%esi),%ecx 253 cmpl %edx,%eax 254 jle LNoEmit2 // iu <= surf->last_u, so nothing to emit 255 256 movl %eax,st_last_u(%ecx) // surf->next->last_u = iu; 257 subl %edx,%eax 258 movl %edx,espan_t_u(%ebp) // span->u = surf->last_u; 259 260 movl %eax,espan_t_count(%ebp) // span->count = iu - span->u; 261 movl C(current_iv),%eax 262 movl %eax,espan_t_v(%ebp) // span->v = current_iv; 263 movl st_spans(%esi),%eax 264 movl %eax,espan_t_pnext(%ebp) // span->pnext = surf->spans; 265 movl %ebp,st_spans(%esi) // surf->spans = span; 266 addl $(espan_t_size),%ebp 267 268 movl st_next(%esi),%edx // remove the surface from the surface 269 movl st_prev(%esi),%esi // stack 270 271 movl %edx,st_next(%esi) 272 movl %esi,st_prev(%edx) 273 ret 274 275LNoEmit2: 276 movl %eax,st_last_u(%ecx) // surf->next->last_u = iu; 277 movl st_next(%esi),%edx // remove the surface from the surface 278 movl st_prev(%esi),%esi // stack 279 280 movl %edx,st_next(%esi) 281 movl %esi,st_prev(%edx) 282 ret 283 284LNoEmit: 285 movl st_next(%esi),%edx // remove the surface from the surface 286 movl st_prev(%esi),%esi // stack 287 288 movl %edx,st_next(%esi) 289 movl %esi,st_prev(%edx) 290 ret 291 292LInverted: 293 movl %eax,st_spanstate(%esi) 294 ret 295 296//-------------------------------------------------------------------- 297 298// trailing edge only 299Lgs_trailing: 300 pushl $Lgs_nextedge 301 jmp TrailingEdge 302 303 304.globl C(R_GenerateSpans) 305C(R_GenerateSpans): 306 pushl %ebp // preserve caller's stack frame 307 pushl %edi 308 pushl %esi // preserve register variables 309 pushl %ebx 310 311// clear active surfaces to just the background surface 312 movl C(surfaces),%eax 313 movl C(edge_head_u_shift20),%edx 314 addl $(st_size),%eax 315// %ebp = span_p throughout 316 movl C(span_p),%ebp 317 318 movl $0,C(r_bmodelactive) 319 320 movl %eax,st_next(%eax) 321 movl %eax,st_prev(%eax) 322 movl %edx,st_last_u(%eax) 323 movl C(edge_head)+et_next,%ebx // edge=edge_head.next 324 325// generate spans 326 cmpl $(C(edge_tail)),%ebx // done if empty list 327 jz Lgs_lastspan 328 329Lgs_edgeloop: 330 331 movl et_surfs(%ebx),%edi 332 movl C(surfaces),%eax 333 movl %edi,%esi 334 andl $0xFFFF0000,%edi 335 andl $0xFFFF,%esi 336 jz Lgs_leading // not a trailing edge 337 338// it has a left surface, so a surface is going away for this span 339 shll $(SURF_T_SHIFT),%esi 340 addl %eax,%esi 341 testl %edi,%edi 342 jz Lgs_trailing 343 344// both leading and trailing 345 call TrailingEdge 346 movl C(surfaces),%eax 347 348// --------------------------------------------------------------- 349// handle a leading edge 350// --------------------------------------------------------------- 351 352Lgs_leading: 353 shrl $16-SURF_T_SHIFT,%edi 354 movl C(surfaces),%eax 355 addl %eax,%edi 356 movl 0x12345678,%esi // surf2 = surfaces[1].next; 357LPatch2: 358 movl st_spanstate(%edi),%edx 359 movl st_insubmodel(%edi),%eax 360 testl %eax,%eax 361 jnz Lbmodel_leading 362 363// handle a leading non-bmodel edge 364 365// don't start a span if this is an inverted span, with the end edge preceding 366// the start edge (that is, we've already seen the end edge) 367 testl %edx,%edx 368 jnz Lxl_done 369 370 371// if (surf->key < surf2->key) 372// goto newtop; 373 incl %edx 374 movl st_key(%edi),%eax 375 movl %edx,st_spanstate(%edi) 376 movl st_key(%esi),%ecx 377 cmpl %ecx,%eax 378 jl Lnewtop 379 380// main sorting loop to search through surface stack until insertion point 381// found. Always terminates because background surface is sentinel 382// do 383// { 384// surf2 = surf2->next; 385// } while (surf->key >= surf2->key); 386Lsortloopnb: 387 movl st_next(%esi),%esi 388 movl st_key(%esi),%ecx 389 cmpl %ecx,%eax 390 jge Lsortloopnb 391 392 jmp LInsertAndExit 393 394 395// handle a leading bmodel edge 396 .align 4 397Lbmodel_leading: 398 399// don't start a span if this is an inverted span, with the end edge preceding 400// the start edge (that is, we've already seen the end edge) 401 testl %edx,%edx 402 jnz Lxl_done 403 404 movl C(r_bmodelactive),%ecx 405 incl %edx 406 incl %ecx 407 movl %edx,st_spanstate(%edi) 408 movl %ecx,C(r_bmodelactive) 409 410// if (surf->key < surf2->key) 411// goto newtop; 412 movl st_key(%edi),%eax 413 movl st_key(%esi),%ecx 414 cmpl %ecx,%eax 415 jl Lnewtop 416 417// if ((surf->key == surf2->key) && surf->insubmodel) 418// { 419 jz Lzcheck_for_newtop 420 421// main sorting loop to search through surface stack until insertion point 422// found. Always terminates because background surface is sentinel 423// do 424// { 425// surf2 = surf2->next; 426// } while (surf->key > surf2->key); 427Lsortloop: 428 movl st_next(%esi),%esi 429 movl st_key(%esi),%ecx 430 cmpl %ecx,%eax 431 jg Lsortloop 432 433 jne LInsertAndExit 434 435// Do 1/z sorting to see if we've arrived in the right position 436 movl et_u(%ebx),%eax 437 subl $0xFFFFF,%eax 438 movl %eax,Ltemp 439 fildl Ltemp 440 441 fmuls float_1_div_0100000h // fu = (float)(edge->u - 0xFFFFF) * 442 // (1.0 / 0x100000); 443 444 fld %st(0) // fu | fu 445 fmuls st_d_zistepu(%edi) // fu*surf->d_zistepu | fu 446 flds C(fv) // fv | fu*surf->d_zistepu | fu 447 fmuls st_d_zistepv(%edi) // fv*surf->d_zistepv | fu*surf->d_zistepu | fu 448 fxch %st(1) // fu*surf->d_zistepu | fv*surf->d_zistepv | fu 449 fadds st_d_ziorigin(%edi) // fu*surf->d_zistepu + surf->d_ziorigin | 450 // fv*surf->d_zistepv | fu 451 452 flds st_d_zistepu(%esi) // surf2->d_zistepu | 453 // fu*surf->d_zistepu + surf->d_ziorigin | 454 // fv*surf->d_zistepv | fu 455 fmul %st(3),%st(0) // fu*surf2->d_zistepu | 456 // fu*surf->d_zistepu + surf->d_ziorigin | 457 // fv*surf->d_zistepv | fu 458 fxch %st(1) // fu*surf->d_zistepu + surf->d_ziorigin | 459 // fu*surf2->d_zistepu | 460 // fv*surf->d_zistepv | fu 461 faddp %st(0),%st(2) // fu*surf2->d_zistepu | newzi | fu 462 463 flds C(fv) // fv | fu*surf2->d_zistepu | newzi | fu 464 fmuls st_d_zistepv(%esi) // fv*surf2->d_zistepv | 465 // fu*surf2->d_zistepu | newzi | fu 466 fld %st(2) // newzi | fv*surf2->d_zistepv | 467 // fu*surf2->d_zistepu | newzi | fu 468 fmuls float_point_999 // newzibottom | fv*surf2->d_zistepv | 469 // fu*surf2->d_zistepu | newzi | fu 470 471 fxch %st(2) // fu*surf2->d_zistepu | fv*surf2->d_zistepv | 472 // newzibottom | newzi | fu 473 fadds st_d_ziorigin(%esi) // fu*surf2->d_zistepu + surf2->d_ziorigin | 474 // fv*surf2->d_zistepv | newzibottom | newzi | 475 // fu 476 faddp %st(0),%st(1) // testzi | newzibottom | newzi | fu 477 fxch %st(1) // newzibottom | testzi | newzi | fu 478 479// if (newzibottom >= testzi) 480// goto Lgotposition; 481 482 fcomp %st(1) // testzi | newzi | fu 483 484 fxch %st(1) // newzi | testzi | fu 485 fmuls float_1_point_001 // newzitop | testzi | fu 486 fxch %st(1) // testzi | newzitop | fu 487 488 fnstsw %ax 489 testb $0x01,%ah 490 jz Lgotposition_fpop3 491 492// if (newzitop >= testzi) 493// { 494 495 fcomp %st(1) // newzitop | fu 496 fnstsw %ax 497 testb $0x45,%ah 498 jz Lsortloop_fpop2 499 500// if (surf->d_zistepu >= surf2->d_zistepu) 501// goto newtop; 502 503 flds st_d_zistepu(%edi) // surf->d_zistepu | newzitop| fu 504 fcomps st_d_zistepu(%esi) // newzitop | fu 505 fnstsw %ax 506 testb $0x01,%ah 507 jz Lgotposition_fpop2 508 509 fstp %st(0) // clear the FPstack 510 fstp %st(0) 511 movl st_key(%edi),%eax 512 jmp Lsortloop 513 514 515Lgotposition_fpop3: 516 fstp %st(0) 517Lgotposition_fpop2: 518 fstp %st(0) 519 fstp %st(0) 520 jmp LInsertAndExit 521 522 523// emit a span (obscures current top) 524 525Lnewtop_fpop3: 526 fstp %st(0) 527Lnewtop_fpop2: 528 fstp %st(0) 529 fstp %st(0) 530 movl st_key(%edi),%eax // reload the sorting key 531 532Lnewtop: 533 movl et_u(%ebx),%eax 534 movl st_last_u(%esi),%edx 535 shrl $20,%eax // iu = integral pixel u 536 movl %eax,st_last_u(%edi) // surf->last_u = iu; 537 cmpl %edx,%eax 538 jle LInsertAndExit // iu <= surf->last_u, so nothing to emit 539 540 subl %edx,%eax 541 movl %edx,espan_t_u(%ebp) // span->u = surf->last_u; 542 543 movl %eax,espan_t_count(%ebp) // span->count = iu - span->u; 544 movl C(current_iv),%eax 545 movl %eax,espan_t_v(%ebp) // span->v = current_iv; 546 movl st_spans(%esi),%eax 547 movl %eax,espan_t_pnext(%ebp) // span->pnext = surf->spans; 548 movl %ebp,st_spans(%esi) // surf->spans = span; 549 addl $(espan_t_size),%ebp 550 551LInsertAndExit: 552// insert before surf2 553 movl %esi,st_next(%edi) // surf->next = surf2; 554 movl st_prev(%esi),%eax 555 movl %eax,st_prev(%edi) // surf->prev = surf2->prev; 556 movl %edi,st_prev(%esi) // surf2->prev = surf; 557 movl %edi,st_next(%eax) // surf2->prev->next = surf; 558 559// --------------------------------------------------------------- 560// leading edge done 561// --------------------------------------------------------------- 562 563// --------------------------------------------------------------- 564// see if there are any more edges 565// --------------------------------------------------------------- 566 567Lgs_nextedge: 568 movl et_next(%ebx),%ebx 569 cmpl $(C(edge_tail)),%ebx 570 jnz Lgs_edgeloop 571 572// clean up at the right edge 573Lgs_lastspan: 574 575// now that we've reached the right edge of the screen, we're done with any 576// unfinished surfaces, so emit a span for whatever's on top 577 movl 0x12345678,%esi // surfaces[1].st_next 578LPatch3: 579 movl C(edge_tail_u_shift20),%eax 580 xorl %ecx,%ecx 581 movl st_last_u(%esi),%edx 582 subl %edx,%eax 583 jle Lgs_resetspanstate 584 585 movl %edx,espan_t_u(%ebp) 586 movl %eax,espan_t_count(%ebp) 587 movl C(current_iv),%eax 588 movl %eax,espan_t_v(%ebp) 589 movl st_spans(%esi),%eax 590 movl %eax,espan_t_pnext(%ebp) 591 movl %ebp,st_spans(%esi) 592 addl $(espan_t_size),%ebp 593 594// reset spanstate for all surfaces in the surface stack 595Lgs_resetspanstate: 596 movl %ecx,st_spanstate(%esi) 597 movl st_next(%esi),%esi 598 cmpl $0x12345678,%esi // &surfaces[1] 599LPatch4: 600 jnz Lgs_resetspanstate 601 602// store the final span_p 603 movl %ebp,C(span_p) 604 605 popl %ebx // restore register variables 606 popl %esi 607 popl %edi 608 popl %ebp // restore the caller's stack frame 609 ret 610 611 612// --------------------------------------------------------------- 613// 1/z sorting for bmodels in the same leaf 614// --------------------------------------------------------------- 615 .align 4 616Lxl_done: 617 incl %edx 618 movl %edx,st_spanstate(%edi) 619 620 jmp Lgs_nextedge 621 622 623 .align 4 624Lzcheck_for_newtop: 625 movl et_u(%ebx),%eax 626 subl $0xFFFFF,%eax 627 movl %eax,Ltemp 628 fildl Ltemp 629 630 fmuls float_1_div_0100000h // fu = (float)(edge->u - 0xFFFFF) * 631 // (1.0 / 0x100000); 632 633 fld %st(0) // fu | fu 634 fmuls st_d_zistepu(%edi) // fu*surf->d_zistepu | fu 635 flds C(fv) // fv | fu*surf->d_zistepu | fu 636 fmuls st_d_zistepv(%edi) // fv*surf->d_zistepv | fu*surf->d_zistepu | fu 637 fxch %st(1) // fu*surf->d_zistepu | fv*surf->d_zistepv | fu 638 fadds st_d_ziorigin(%edi) // fu*surf->d_zistepu + surf->d_ziorigin | 639 // fv*surf->d_zistepv | fu 640 641 flds st_d_zistepu(%esi) // surf2->d_zistepu | 642 // fu*surf->d_zistepu + surf->d_ziorigin | 643 // fv*surf->d_zistepv | fu 644 fmul %st(3),%st(0) // fu*surf2->d_zistepu | 645 // fu*surf->d_zistepu + surf->d_ziorigin | 646 // fv*surf->d_zistepv | fu 647 fxch %st(1) // fu*surf->d_zistepu + surf->d_ziorigin | 648 // fu*surf2->d_zistepu | 649 // fv*surf->d_zistepv | fu 650 faddp %st(0),%st(2) // fu*surf2->d_zistepu | newzi | fu 651 652 flds C(fv) // fv | fu*surf2->d_zistepu | newzi | fu 653 fmuls st_d_zistepv(%esi) // fv*surf2->d_zistepv | 654 // fu*surf2->d_zistepu | newzi | fu 655 fld %st(2) // newzi | fv*surf2->d_zistepv | 656 // fu*surf2->d_zistepu | newzi | fu 657 fmuls float_point_999 // newzibottom | fv*surf2->d_zistepv | 658 // fu*surf2->d_zistepu | newzi | fu 659 660 fxch %st(2) // fu*surf2->d_zistepu | fv*surf2->d_zistepv | 661 // newzibottom | newzi | fu 662 fadds st_d_ziorigin(%esi) // fu*surf2->d_zistepu + surf2->d_ziorigin | 663 // fv*surf2->d_zistepv | newzibottom | newzi | 664 // fu 665 faddp %st(0),%st(1) // testzi | newzibottom | newzi | fu 666 fxch %st(1) // newzibottom | testzi | newzi | fu 667 668// if (newzibottom >= testzi) 669// goto newtop; 670 671 fcomp %st(1) // testzi | newzi | fu 672 673 fxch %st(1) // newzi | testzi | fu 674 fmuls float_1_point_001 // newzitop | testzi | fu 675 fxch %st(1) // testzi | newzitop | fu 676 677 fnstsw %ax 678 testb $0x01,%ah 679 jz Lnewtop_fpop3 680 681// if (newzitop >= testzi) 682// { 683 684 fcomp %st(1) // newzitop | fu 685 fnstsw %ax 686 testb $0x45,%ah 687 jz Lsortloop_fpop2 688 689// if (surf->d_zistepu >= surf2->d_zistepu) 690// goto newtop; 691 692 flds st_d_zistepu(%edi) // surf->d_zistepu | newzitop | fu 693 fcomps st_d_zistepu(%esi) // newzitop | fu 694 fnstsw %ax 695 testb $0x01,%ah 696 jz Lnewtop_fpop2 697 698Lsortloop_fpop2: 699 fstp %st(0) // clear the FP stack 700 fstp %st(0) 701 movl st_key(%edi),%eax 702 jmp Lsortloop 703 704 705.globl C(R_EdgeCodeEnd) 706C(R_EdgeCodeEnd): 707 708 709//---------------------------------------------------------------------- 710// Surface array address code patching routine 711//---------------------------------------------------------------------- 712 713 .align 4 714.globl C(R_SurfacePatch) 715C(R_SurfacePatch): 716 717 movl C(surfaces),%eax 718 addl $(st_size),%eax 719 movl %eax,LPatch4-4 720 721 addl $(st_next),%eax 722 movl %eax,LPatch0-4 723 movl %eax,LPatch2-4 724 movl %eax,LPatch3-4 725 726 ret 727 728#endif // id386 729 730